lastest code with cf23f4f9

This commit is contained in:
venba-Inspriron-3558 2025-07-29 15:24:58 +05:30
parent cf23f4f936
commit d2b3b792d9
33 changed files with 15896 additions and 3395 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -931,7 +931,12 @@ class _ApprovalListState extends State<ApprovalList> {
builder: (context, constraints) {
double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox(
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child:
ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth),
child: DataTable(
dividerThickness: 0.5,
@ -1416,7 +1421,7 @@ class _ApprovalListState extends State<ApprovalList> {
);
}).toList(),
),
);
)));
},
);
@ -1647,7 +1652,7 @@ class _ApprovalListState extends State<ApprovalList> {
CrossAxisAlignment.end,
children: [
Column(
Flexible( child:Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
@ -1666,7 +1671,7 @@ class _ApprovalListState extends State<ApprovalList> {
),
),
],
),
),),
Column(
mainAxisAlignment:
MainAxisAlignment.end,

File diff suppressed because it is too large Load Diff

View File

@ -491,33 +491,40 @@ class StatusDashboardState extends State<StatusDashboard> {
}
Widget statusCard(String label, int count, bool isDesktop) {
return Container(
return SizedBox(
width: isDesktop ? 120 : double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
decoration: BoxDecoration(
color: const Color(0xFFEAF3FB),
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Text(
count.toString(),
style: GoogleFonts.poppins(
fontSize: isDesktop ? 18 : 16,
color: Colors.black87,
fontWeight: FontWeight.bold,
height: isDesktop ? 100 : 100, // fixed height for all cards
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFEAF3FB),
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // vertically center everything
children: [
Text(
count.toString(),
style: GoogleFonts.poppins(
fontSize: isDesktop ? 18 : 16,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 5),
Text(
label,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: isDesktop ? 12 : 11,
color: Colors.black87,
const SizedBox(height: 6),
Text(
label,
maxLines: 2,
overflow: TextOverflow.ellipsis,
softWrap: true,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: isDesktop ? 12 : 11,
color: Colors.black87,
),
),
),
],
],
),
),
);
}

View File

@ -613,13 +613,13 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
CustomTextFieldItnerarySubWrapper(
isFocused: _destinationFocused,
isDesktop: isDesktop,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: TextField(
@ -1164,7 +1164,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
child: GestureDetector(
onTap: () {
_checkInTimeFocusNode.requestFocus();
_checkInTimeController.text = "";
// _checkInTimeController.text = ""; // pavithra told me. here client reported the issues here thats why.
_selectCheckInTime(context);
},
child: AbsorbPointer(
@ -1326,13 +1326,14 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
// CustomTextFieldWrapper
CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null, // MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: TextField(

View File

@ -647,7 +647,7 @@ class _BusScreenState extends State<BusScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : null,

File diff suppressed because it is too large Load Diff

View File

@ -2198,7 +2198,7 @@ class _ForexScreenState extends State<ForexScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
CustomTextFieldForexWrapper(
isFocused:
focusStates["_comments"] ?? false, // Dropdown doesn't use focus
isDesktop: isDesktop,
@ -2301,7 +2301,7 @@ class _ForexScreenState extends State<ForexScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
CustomTextFieldForexWrapper(
isFocused:
focusStates["_deliveryLocation"] ??
false, // Dropdown doesn't use focus
@ -2344,7 +2344,7 @@ class _ForexScreenState extends State<ForexScreen> {
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: isDesktop ? MainAxisAlignment.center : MainAxisAlignment.start,
children: [
Container(
alignment: Alignment.bottomLeft,

View File

@ -1333,7 +1333,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.31
: MediaQuery.of(context).size.width * 0.66,
: null, // MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: TextField(

View File

@ -309,7 +309,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
width: double.infinity,
@ -432,13 +432,14 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
// CustomTextFieldWrapper
CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: TextField(

View File

@ -603,7 +603,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
width: double.infinity,
@ -1019,13 +1019,13 @@ class _TaxiScreenState extends State<TaxiScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,

View File

@ -456,7 +456,7 @@ class _TrainScreenState extends State<TrainScreen> {
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [
CustomTextFieldWrapper(
CustomTextFieldItnerarySubWrapper(
isFocused: _trainNoFocused,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,
@ -653,7 +653,8 @@ class _TrainScreenState extends State<TrainScreen> {
// ),
// ),
// ),
CustomTextFieldWrapper(
// CustomTextFieldWrapper
CustomTextFieldItnerarySubWrapper(
isFocused: _typeOfClassFocus,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: isDesktop,
@ -1332,7 +1333,7 @@ class _TrainScreenState extends State<TrainScreen> {
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,

View File

@ -542,14 +542,14 @@ class _VisaScreenState extends State<VisaScreen> {
// ),
// ),
// ),
CustomTextFieldItnerarySubWrapper(
CustomTextFieldWrapper(
isFocused: _isHotelNameFocused,
isDesktop: isDesktop,
padding: const EdgeInsets.symmetric(horizontal: 0),
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: Focus(
@ -586,7 +586,7 @@ class _VisaScreenState extends State<VisaScreen> {
vertical: 6,
),
child: Padding(
padding: const EdgeInsets.only(right: 4.0),
padding: const EdgeInsets.only(right: 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -927,7 +927,7 @@ class _VisaScreenState extends State<VisaScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
: null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: TextField(

View File

@ -34,10 +34,15 @@ class AccomodationListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Text(
// "Accomodation Booking List",
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
// ),
if ((!isDesktop) && accommodationList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
@ -64,6 +69,24 @@ class AccomodationListWidget extends StatelessWidget {
size: 30,
color: Color(0xFF114D8B),
)
// Container(
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// border: Border.all(
// color: Color(0xFF114D8B), // Outline color
// width: 2, // Outline thickness
// ),
// ),
// height: 30,
// width: 30,
// child: Center(
// child: Icon(
// Icons.add,
// size: 20,
// color: Colors.black,
// ),
// ),
// ),
],
),
),
@ -240,7 +263,7 @@ class AccomodationListWidget extends StatelessWidget {
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: Color(0xFF575A74)),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),)
),
Spacer(),
GestureDetector(
@ -251,6 +274,7 @@ class AccomodationListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
),
),
),
@ -263,6 +287,7 @@ class AccomodationListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
@ -356,21 +381,82 @@ class AccomodationListWidget extends StatelessWidget {
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow("City:", item["destination_city"]),
SizedBox(width: 10),
SizedBox(width: 10),
_buildDateTimeRow(
"Check-in:",
formatDate(item["checkin_date"]!),
item["checkin_time"]!,
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
children: [
_buildInfoColumn("City", item["destination_city"]),
_buildInfoColumn("Check (In)", "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}"),
_buildInfoColumn("Check (Out)", "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}"),
// City - long name handled with flexible space
// Expanded(
// flex: 3,
// child: _buildInfoColumn("City", item["destination_city"]),
// ),
// SizedBox(width: 8),
// Check In and Check Out stacked right side
// Expanded(
// flex: 4,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// _buildInfoColumn(
// "Check In",
// "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}",
// ),
// SizedBox(height: 6),
// _buildInfoColumn(
// "Check Out",
// "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}",
// ),
// ],
// ),
// ),
],
),
SizedBox(width: 10),
_buildRow(
"Date(out):", formatDate(item["checkout_date"]!)),
SizedBox(width: 10),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
const SizedBox(height: 10),
const Text(
"Comment",
style: TextStyle(fontWeight: FontWeight.w500),
),
const SizedBox(height: 5),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(color: Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"],
style: const TextStyle(fontSize: 12),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
)
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow("City:", item["destination_city"]),
// SizedBox(width: 10),
// SizedBox(width: 10),
// _buildDateTimeRow(
// "Check-in:",
// formatDate(item["checkin_date"]!),
// item["checkin_time"]!,
// ),
// SizedBox(width: 10),
// _buildRow(
// "Date(out):", formatDate(item["checkout_date"]!)),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// )
],
),
),
@ -429,78 +515,103 @@ class AccomodationListWidget extends StatelessWidget {
);
}
Widget _buildRow(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {
// "Special Request:": 30,
"Comments:": 10,
// Add more keys and limits if needed
};
int limit = limits[title] ?? 50; // Default limit if title not found
bool exceedsLimit = value.length > limit;
String wrapText(String text, int maxLineLength) {
final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
}
return Row(
// Helper widget
Widget _buildInfoColumn(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
SizedBox(width: 8),
Expanded(
child: exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle:
TextStyle(color: Colors.black), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(value.substring(0, limit) + "...",
style: TextStyle(fontSize: 12),
overflow: TextOverflow.ellipsis),
)
: Text(
value,
style: TextStyle(fontSize: 12),
),
SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
);
}
Widget _buildDateTimeRow(String title, String date, String time) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
SizedBox(width: 8),
Expanded(
child: Text(
"$date, $time",
style: GoogleFonts.poppins(
fontSize: 12,
),
),
),
],
);
}
// Widget _buildRow(String title, String value) {
// // Define character limits based on title
// Map<String, int> limits = {
// // "Special Request:": 30,
// "Comments:": 10,
// // Add more keys and limits if needed
// };
//
// int limit = limits[title] ?? 50; // Default limit if title not found
// bool exceedsLimit = value.length > limit;
//
// String wrapText(String text, int maxLineLength) {
// final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
// return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
// }
//
// return Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// title,
// style: GoogleFonts.poppins(
// fontSize: 12,
// ),
// ),
// SizedBox(width: 8),
// Expanded(
// child: exceedsLimit
// ? Tooltip(
// message: wrapText(value, 50),
// decoration: BoxDecoration(
// color: Colors.grey.shade200, // Black background
// borderRadius: BorderRadius.circular(6),
// ),
// textStyle:
// TextStyle(color: Colors.black), // Tooltip text color
// padding: EdgeInsets.all(8),
// preferBelow: false,
// child: Text(value.substring(0, limit) + "...",
// style: TextStyle(fontSize: 12),
// overflow: TextOverflow.ellipsis),
// )
// : Text(
// value,
// style: TextStyle(fontSize: 12),
// ),
// ),
// ],
// );
// }
// Widget _buildDateTimeRow(String title, String date, String time) {
// return Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// title,
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// SizedBox(width: 8),
// Expanded(
// child: Text(
// "$date, $time",
// style: GoogleFonts.poppins(
// fontSize: 12,
// ),
// ),
// ),
// ],
// );
// }
}

View File

@ -40,6 +40,15 @@ class BusListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && busList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
@ -65,6 +74,24 @@ class BusListWidget extends StatelessWidget {
size: 30,
color: Color(0xFF114D8B),
)
// Container(
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// border: Border.all(
// color: Color(0xFF114D8B), // Outline color
// width: 2, // Outline thickness
// ),
// ),
// height: 30,
// width: 30,
// child: Center(
// child: Icon(
// Icons.add,
// size: 20,
// color: Colors.black,
// ),
// ),
// ),
],
),
),
@ -230,6 +257,8 @@ class BusListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
// color: Color(0xFF114D8B),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
),
),
),
@ -242,6 +271,7 @@ class BusListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
@ -314,21 +344,70 @@ class BusListWidget extends StatelessWidget {
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow("From:", item["from"]),
SizedBox(width: 10),
_buildRow("To:", item["to"]!),
SizedBox(width: 10),
_buildDateTimeRow(
"Date:",
formatDate(item["date"]!),
formatTime(item["time"]!),
),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row (Country, Currency, Total)
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoBlock("From", item["from"] ?? "N/A"),
_infoBlock("To", item["to"]! ?? "N/A"),
_infoBlock("Date",
(item["date"] != null && item["time"] != null)
? "${formatDate(item["date"]!)} ${formatTime(item["time"]!)}"
: "N/A",
),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow("From:", item["from"]),
// SizedBox(width: 10),
// _buildRow("To:", item["to"]!),
// SizedBox(width: 10),
// _buildDateTimeRow(
// "Date:",
// formatDate(item["date"]!),
// formatTime(item["time"]!),
// ),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// )
],
),
),
@ -337,6 +416,34 @@ class BusListWidget extends StatelessWidget {
);
}
Widget _infoBlock(String label, String value) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
),
),
);
}
Widget _buildComments(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {

View File

@ -108,6 +108,66 @@ class _FlightListWidgetState extends State<FlightListWidget> {
}
}
// return Padding(
// padding: const EdgeInsets.all(16.0),
// child: Container(
// margin: const EdgeInsets.only(top: 16.0),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// // Header with title and button
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// "Flight",
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
// ),
// widget.flightList.isNotEmpty
// ? MouseRegion(
// cursor:
// widget.isViewMode
// ? SystemMouseCursors.forbidden
// : SystemMouseCursors.click,
// child: GestureDetector(
// onTap:
// widget.isViewMode
// ? null
// : () {
// widget.onAddNew("Flight", true);
// // checkClass();
// print("New data");
// },
// child: Row(
// mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely
// children: [
// // Text(
// // "Add New",
// // style: TextStyle(fontSize: 13),
// // ),
// // SizedBox(width: 8), // spacing between icon and text
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// ),
// ],
// ),
// ),
// )
// : SizedBox.shrink(),
// ],
// ),
// const SizedBox(height: 16),
//
// // Scroll behavior based on device
// _buildData(context, isDesktop),
// ],
// ),
// ),
// );
return Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
@ -115,58 +175,67 @@ class _FlightListWidgetState extends State<FlightListWidget> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header with title and button
// Row: Title (mobile only) + Add Button (conditional)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Text(
// "Flight Booking List",
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
// ),
widget.flightList.isNotEmpty
? MouseRegion(
cursor:
widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap:
widget.isViewMode
? null
: () {
widget.onAddNew("Flight", true);
// checkClass();
print("New data");
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text(
// "Add New",
// style: TextStyle(fontSize: 13),
// ),
// SizedBox(width: 8), // spacing between icon and text
Icon(
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
),
],
// Title (optional on desktop or mobile)
if ((!isDesktop) && widget.flightList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
// Right side: either "Add" icon or nothing
if (widget.flightList.isNotEmpty)
MouseRegion(
cursor: widget.isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: widget.isViewMode
? null
: () {
widget.onAddNew("Flight", true);
print("New data");
},
child: Icon(
Icons.add_circle_sharp,
size: 30,
color: const Color(0xFF114D8B),
),
),
)
else if (!isDesktop)
// Centered "No Data Found" message for mobile and empty list
Expanded(
child: Center(
child: Text(
"No Data Found",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.grey,
),
),
)
: SizedBox.shrink(),
),
)
],
),
const SizedBox(height: 16),
// Scroll behavior based on device
// Actual flight data UI
_buildData(context, isDesktop),
],
),
),
);
}
Widget _buildData(BuildContext context, bool isDesktop) {
@ -313,6 +382,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),
),
),
Spacer(),
@ -324,6 +394,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
),
),
),
@ -336,6 +407,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
@ -559,40 +631,175 @@ class _FlightListWidgetState extends State<FlightListWidget> {
final tocity = tocityMatch?.group(1) ?? '';
final tocode = tocityMatch?.group(2) ?? '';
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 6.0),
// child: Container(
// decoration: BoxDecoration(
// border: Border.all(color: Colors.grey.shade300),
// borderRadius: BorderRadius.circular(6),
// color: Colors.grey.shade50,
// ),
// padding: const EdgeInsets.all(8),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildKeyValueRow(
// "Class",
// getRequestForClass(trip["class"].toString()) ??
// "N/A",
// ),
// _buildKeyValueRow(
// "Sector",
// "$fromcity ($fromcode), $fromairport$tocity ($tocode), $toairport",
// ),
//
// _buildKeyValueRow(
// "Date",
// formatDate(trip["date"] ?? ""),
// ),
// _buildKeyValueRow(
// "Time",
// formatTime(trip["time"] ?? ""),
// ),
// ],
// ),
// ),
// );
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 6.0),
// child: Container(
// // decoration: BoxDecoration(
// // border: Border.all(color: Colors.grey.shade300),
// // borderRadius: BorderRadius.circular(6),
// // color: Colors.grey.shade50,
// // ),
// // padding: const EdgeInsets.all(12),
// child: Row(
// children: [
// /// LEFT SIDE: Class and Airport Info
// Expanded(
// flex: 2,
// child: Row(
// children: [
// Text(
// '${getRequestForClass(trip["class"].toString()) ?? "N/A"} (',
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 14,
// color: Colors.black87,
// ),
// ),
// Text(
// // fromairport,
// fromcode,
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 14,
// color: Colors.black87,
// ),
// ),
// const Padding(
// padding: EdgeInsets.symmetric(horizontal: 6),
// child: Image(
// image: AssetImage('assets/images/IconsImg/Frame.png'),
// width: 18,
// height: 18,
// ),
// ),
// Text(
// '$tocode)',
// // '$toairport)',
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 14,
// color: Colors.black87,
// ),
// ),
// ],
// ),
// ),
//
// /// RIGHT SIDE: Date and Time
// Expanded(
// flex: 1,
// child: Text(
// '${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}',
// textAlign: TextAlign.right,
// style: const TextStyle(
// fontSize: 13,
// color: Colors.black87,
// ),
// ),
// ),
// ],
// ),
// ),
// );
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(6),
color: Colors.grey.shade50,
),
padding: const EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildKeyValueRow(
"Class",
getRequestForClass(trip["class"].toString()) ??
"N/A",
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
runSpacing: 4,
children: [
Text(
'${getRequestForClass(trip["class"].toString()) ?? "N/A"} (',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.black87,
),
),
Text(
fromcode,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.black87,
),
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 4),
child: Image(
image: AssetImage('assets/images/IconsImg/Frame.png'),
width: 18,
height: 18,
),
),
Text(
'$tocode)',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.black87,
),
),
],
),
_buildKeyValueRow(
"Sector",
"$fromcity ($fromcode), $fromairport$tocity ($tocode), $toairport",
),
_buildKeyValueRow(
"Date",
formatDate(trip["date"] ?? ""),
),
_buildKeyValueRow(
"Time",
formatTime(trip["time"] ?? ""),
const SizedBox(height: 6),
Align(
alignment: Alignment.centerRight,
child: Text(
'${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}',
textAlign: TextAlign.right,
style: const TextStyle(
fontSize: 13,
color: Colors.black87,
),
),
),
],
),
),
);
}).toList(),
],
),

View File

@ -39,93 +39,101 @@ class ForexListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header with title and button
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: isViewMode
? null
: () {
print("New data");
onAddNew("Forex", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text(
// "Add New",
// style: TextStyle(fontSize: 13),
// ),
// SizedBox(width: 8), // spacing between icon and text
Icon(
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
)
],
),
),
// onPressed: isViewMode
// ? null
// : () {
// print("New data");
//
// },
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
// ],
// ),
),
// MouseRegion(
// cursor: isViewMode
// ? SystemMouseCursors.forbidden
// : SystemMouseCursors.click,
// child: ElevatedButton(
// style: ElevatedButton.styleFrom(
// backgroundColor: Color(0xFF114D8B),
// foregroundColor: Colors.white,
// disabledBackgroundColor: Color(0xFF114D8B),
// disabledForegroundColor: Colors.white,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(8),
// side: BorderSide(color: Color(0xFF114D8B), width: 2),
// ),
// padding:
// EdgeInsets.symmetric(horizontal: 20, vertical: 12),
// ),
// onPressed: isViewMode
// ? null
// : () {
// print("New data");
// onAddNew("Forex", true);
// },
// child: Row(
// mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely
// children: [
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
// ],
// ),
// ),
// ),
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// if ((!isDesktop) && forexList.isNotEmpty)
// Text(
// " ",
// style: const TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// ),
// ),
// MouseRegion(
// cursor: isViewMode
// ? SystemMouseCursors.forbidden
// : SystemMouseCursors.click,
//
// child: GestureDetector(
// onTap: isViewMode
// ? null
// : () {
// print("New data");
// onAddNew("Forex", true);
// },
// child: Row(
// mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely
// children: [
// // Text(
// // "Add New",
// // style: TextStyle(fontSize: 13),
// // ),
// // SizedBox(width: 8), // spacing between icon and text
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
// ],
// ),
// ),
// // onPressed: isViewMode
// // ? null
// // : () {
// // print("New data");
// //
// // },
// // child: Row(
// // mainAxisSize: MainAxisSize.min,
// // children: [
// // Icon(
// // Icons.add_circle_sharp,
// // size: 30,
// // color: Color(0xFF114D8B),
// // )
// // ],
// // ),
// ),
// // MouseRegion(
// // cursor: isViewMode
// // ? SystemMouseCursors.forbidden
// // : SystemMouseCursors.click,
// // child: ElevatedButton(
// // style: ElevatedButton.styleFrom(
// // backgroundColor: Color(0xFF114D8B),
// // foregroundColor: Colors.white,
// // disabledBackgroundColor: Color(0xFF114D8B),
// // disabledForegroundColor: Colors.white,
// // shape: RoundedRectangleBorder(
// // borderRadius: BorderRadius.circular(8),
// // side: BorderSide(color: Color(0xFF114D8B), width: 2),
// // ),
// // padding:
// // EdgeInsets.symmetric(horizontal: 20, vertical: 12),
// // ),
// // onPressed: isViewMode
// // ? null
// // : () {
// // print("New data");
// // onAddNew("Forex", true);
// // },
// // child: Row(
// // mainAxisSize:
// // MainAxisSize.min, // Ensures content fits nicely
// // children: [
// // Icon(
// // Icons.add_circle_sharp,
// // size: 30,
// // color: Color(0xFF114D8B),
// // )
// // ],
// // ),
// // ),
// // ),
// ],
// ),
const SizedBox(height: 16),
// Scroll behavior based on device
@ -275,21 +283,24 @@ class ForexListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
// color: Color(0xFF114D8B),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => onDeleteForex(item),
child: Tooltip(
message: 'Delete Forex Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () => onDeleteForex(item),
// child: Tooltip(
// message: 'Delete Forex Details',
// child: Image.asset(
// 'assets/images/IconsImg/delete.png',
// width: 20,
// height: 15,
// color: Colors.red,
// ),
// ),
// ),
item['forex_id'] != null
? IconButton(
icon: Icon(Icons.download,
@ -495,30 +506,84 @@ class ForexListWidget extends StatelessWidget {
"Comments:", item["comments"] ?? "N/A"),
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow(
"Currency:",
item["currency"],
),
// SizedBox(height: 6),
_buildRow(
"Duration:",
item["duration"],
),
// SizedBox(height: 6),
_buildRow("StartDate:", item["start_date"]!),
_buildRow("EndDate:", item["end_date"]!),
_buildRow("Perdiem:", "$perdiemAmount",),
_buildRow("Others:", "$calculatedOtherExpenses"),
_buildRow("Total:", "$finalTotal"),
_buildRow("Cash:", item["deposit_on_cash"]!),
_buildRow("Card:", item["deposit_on_card"]!),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
): Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row (Country, Currency, Total)
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoBlock("Country code", item["country_code"] ?? "N/A"),
_infoBlock("Currency", item["currency"] ?? "N/A"),
_infoBlock("Total Amount", item["total_amount"]?.toString() ?? "0"),
],
),
const SizedBox(height: 12),
// Second Row (Start Date, End Date, Duration)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoBlock("Start Date", item["start_date"] ?? "N/A"),
_infoBlock("End Date", item["end_date"] ?? "N/A"),
_infoBlock("Duration", item["duration"]?.toString() ?? "N/A"),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
),
// old code
// : Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow(
// "Currency:",
// item["currency"],
// ),
// // SizedBox(height: 6),
// _buildRow(
// "Duration:",
// item["duration"],
// ),
// // SizedBox(height: 6),
// _buildRow("StartDate:", item["start_date"]!),
// _buildRow("EndDate:", item["end_date"]!),
// _buildRow("Perdiem:", "$perdiemAmount",),
// _buildRow("Others:", "$calculatedOtherExpenses"),
// _buildRow("Total:", "$finalTotal"),
// _buildRow("Cash:", item["deposit_on_cash"]!),
// _buildRow("Card:", item["deposit_on_card"]!),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
],
),
),
@ -577,59 +642,89 @@ class ForexListWidget extends StatelessWidget {
);
}
Widget _buildRow(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {
// "Special Request:": 30,
"Comments:": 10,
// Add more keys and limits if needed
};
int limit = limits[title] ?? 50; // Default limit if title not found
bool exceedsLimit = value.length > limit;
String wrapText(String text, int maxLineLength) {
final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
}
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
Widget _infoBlock(String label, String value) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
),
SizedBox(width: 8),
Expanded(
child: exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle:
TextStyle(color: Colors.black), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(value.substring(0, limit) + "...",
style: GoogleFonts.poppins(
fontSize: 12,
),
overflow: TextOverflow.ellipsis),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
),
),
),
],
),
);
}
// Widget _buildRow(String title, String value) {
// // Define character limits based on title
// Map<String, int> limits = {
// // "Special Request:": 30,
// "Comments:": 10,
// // Add more keys and limits if needed
// };
//
// int limit = limits[title] ?? 50; // Default limit if title not found
// bool exceedsLimit = value.length > limit;
//
// String wrapText(String text, int maxLineLength) {
// final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
// return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
// }
//
// return Row(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// title,
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// SizedBox(width: 8),
// Expanded(
// child: exceedsLimit
// ? Tooltip(
// message: wrapText(value, 50),
// decoration: BoxDecoration(
// color: Colors.grey.shade200, // Black background
// borderRadius: BorderRadius.circular(6),
// ),
// textStyle:
// TextStyle(color: Colors.black), // Tooltip text color
// padding: EdgeInsets.all(8),
// preferBelow: false,
// child: Text(value.substring(0, limit) + "...",
// style: GoogleFonts.poppins(
// fontSize: 12,
// ),
// overflow: TextOverflow.ellipsis),
// )
// : Text(
// value,
// style: GoogleFonts.poppins(
// fontSize: 12,
// ),
// ),
// ),
// ],
// );
// }
}

View File

@ -34,71 +34,79 @@ class InsuranceListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header with title and button
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: isViewMode
? null
: () {
print("New data");
onAddNew("Insurance", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text(
// "Add New",
// style: TextStyle(fontSize: 13),
// ),
// SizedBox(width: 8), // spacing between icon and text
Icon(
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
)
],
),
),
// child: ElevatedButton(
// style: ElevatedButton.styleFrom(
// backgroundColor: Color(0xFF114D8B),
// foregroundColor: Colors.white,
// disabledBackgroundColor: Color(0xFF114D8B),
// disabledForegroundColor: Colors.white,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(8),
// side: BorderSide(color: Color(0xFF114D8B), width: 2),
// ),
// padding:
// EdgeInsets.symmetric(horizontal: 20, vertical: 12),
// ),
// onPressed: isViewMode
// ? null
// : () {
// print("New data");
// onAddNew("Insurance", true);
// },
// child: Row(
// mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely
// children: [
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
// ],
// ),
// ),
),
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// if ((!isDesktop) && insuranceList.isNotEmpty)
// Text(
// " ",
// style: const TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// ),
// ),
// MouseRegion(
// cursor: isViewMode
// ? SystemMouseCursors.forbidden
// : SystemMouseCursors.click,
// child: GestureDetector(
// onTap: isViewMode
// ? null
// : () {
// print("New data");
// onAddNew("Insurance", true);
// },
// child: Row(
// mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely
// children: [
// // Text(
// // "Add New",
// // style: TextStyle(fontSize: 13),
// // ),
// // SizedBox(width: 8), // spacing between icon and text
// // Icon(
// // Icons.add_circle_sharp,
// // size: 30,
// // color: Color(0xFF114D8B),
// // )
// ],
// ),
// ),
// // child: ElevatedButton(
// // style: ElevatedButton.styleFrom(
// // backgroundColor: Color(0xFF114D8B),
// // foregroundColor: Colors.white,
// // disabledBackgroundColor: Color(0xFF114D8B),
// // disabledForegroundColor: Colors.white,
// // shape: RoundedRectangleBorder(
// // borderRadius: BorderRadius.circular(8),
// // side: BorderSide(color: Color(0xFF114D8B), width: 2),
// // ),
// // padding:
// // EdgeInsets.symmetric(horizontal: 20, vertical: 12),
// // ),
// // onPressed: isViewMode
// // ? null
// // : () {
// // print("New data");
// // onAddNew("Insurance", true);
// // },
// // child: Row(
// // mainAxisSize:
// // MainAxisSize.min, // Ensures content fits nicely
// // children: [
// // Icon(
// // Icons.add_circle_sharp,
// // size: 30,
// // color: Color(0xFF114D8B),
// // )
// // ],
// // ),
// // ),
// ),
// ],
// ),
const SizedBox(height: 16),
// Scroll behavior based on device
@ -197,6 +205,7 @@ class InsuranceListWidget extends StatelessWidget {
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
),
),
Spacer(),
@ -208,21 +217,23 @@ class InsuranceListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
),
),
),
SizedBox(width: 10),
GestureDetector(
onTap: () => onDeleteInsurance(item),
child: Tooltip(
message: 'Delete Insurance Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () => onDeleteInsurance(item),
// child: Tooltip(
// message: 'Delete Insurance Details',
// child: Image.asset(
// 'assets/images/IconsImg/delete.png',
// width: 20,
// height: 15,
// color: Colors.red,
// ),
// ),
// ),
],
),
SizedBox(height: 4),
@ -293,21 +304,65 @@ class InsuranceListWidget extends StatelessWidget {
),
],
)
: Column(
children: [
_buildRow(
"InsuranceType:",
getRequestForInsuranceType(
item["type_of_insurance"]!.toString())),
SizedBox(width: 10),
_buildRow(
"StartDate:", formatDate(item["start_date"]!)),
SizedBox(width: 10),
_buildRow("EndDate:", formatDate(item["end_date"])),
SizedBox(width: 10),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row (Country, Currency, Total)
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
children: [
_infoBlock("Insurance Type", getRequestForInsuranceType(item["type_of_insurance"]!.toString()) ?? "N/A"),
_infoBlock("Start Date", formatDate(item["start_date"]!) ?? "N/A"),
_infoBlock("End Date", formatDate(item["end_date"]) ?? "N/A"),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
),
// Column(
// children: [
// _buildRow(
// "InsuranceType:",
// getRequestForInsuranceType(
// item["type_of_insurance"]!.toString())),
// SizedBox(width: 10),
// _buildRow(
// "StartDate:", formatDate(item["start_date"]!)),
// SizedBox(width: 10),
// _buildRow("EndDate:", formatDate(item["end_date"])),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
],
),
),
@ -366,6 +421,34 @@ class InsuranceListWidget extends StatelessWidget {
);
}
Widget _infoBlock(String label, String value) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
),
),
);
}
Widget _buildRow(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {

View File

@ -26,56 +26,67 @@ class MiscellaneousListWidget extends StatelessWidget {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
// color: Color(0xFFE8F0FC),
margin: const EdgeInsets.only(top: 28.0),
padding: const EdgeInsets.all(10.0),
margin: const EdgeInsets.only(top: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Header with title and button
Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && miscellaneousList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion(
cursor:
isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap:
isViewMode
? null
: () {
print("New data");
onAddNew("Miscellaneous", true);
},
isViewMode
? null
: () {
print("New data");
onAddNew("Miscellaneous", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text(
// "Add New",
// style: TextStyle(fontSize: 13),
// ),
// SizedBox(width: 8), // spacing between icon and text
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Color(0xFF114D8B), // Outline color
width: 2, // Outline thickness
),
),
height: 30,
width: 30,
child: Center(
child: Icon(
Icons.add,
size: 20,
color: Colors.black,
),
),
Icon(
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
),
// Container(
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// border: Border.all(
// color: Color(0xFF114D8B), // Outline color
// width: 2, // Outline thickness
// ),
// ),
// height: 30,
// width: 30,
// child: Center(
// child: Icon(
// Icons.add,
// size: 20,
// color: Colors.black,
// ),
// ),
// ),
],
),
),
@ -122,7 +133,7 @@ class MiscellaneousListWidget extends StatelessWidget {
Widget _buildData(BuildContext context, bool isDesktop) {
List<Map<String, dynamic>> filteredList =
miscellaneousList.where((item) => item["is_active"] == "1").toList();
miscellaneousList.where((item) => item["is_active"] == "1").toList();
return ListView.builder(
shrinkWrap: true,
@ -136,9 +147,9 @@ class MiscellaneousListWidget extends StatelessWidget {
return (apiData?['miscellaneous_special_request'] ?? [])
.firstWhere(
(element) =>
element["dropdown_key"].toString() == specialRequestKey,
orElse: () => {"dropdown_value": "N/A"},
)["dropdown_value"]
element["dropdown_key"].toString() == specialRequestKey,
orElse: () => {"dropdown_value": "N/A"},
)["dropdown_value"]
.toString();
}
@ -174,8 +185,7 @@ class MiscellaneousListWidget extends StatelessWidget {
getRequestValue(item["special_request"]?.toString()),
style: GoogleFonts.poppins(
fontSize: 14,
color: Color(0xFF114D8B),
fontWeight: FontWeight.w500,
fontWeight: FontWeight.w800,
),
),
Spacer(),
@ -187,6 +197,7 @@ class MiscellaneousListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
),
),
),
@ -200,83 +211,101 @@ class MiscellaneousListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
],
),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 10),
isDesktop
? Row(
children: [
// Expanded(
// flex: 2,
// child: Text(
// "Special Request",
// style: GoogleFonts.poppins(fontSize: 11),
// ),
// ),
Expanded(
flex: 3,
child: Text(
"Comments",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w600,
),
),
),
],
)
: SizedBox.shrink(),
Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Container(
// color: Color(0xFFE8F0FC),
color: Colors.white,
child: Expanded(
child: Row(
children: [
// Expanded(
// flex: 2,
// child: Text(
// getRequestValue(
// item["special_request"]?.toString(),
// ),
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
Container(
// width: MediaQuery.of(context).size.width * 0.6,
// padding: EdgeInsets.all(16),
// color: Color(0xFFE8F0FC),
child: Expanded(
// flex: 1,
child: Text(
item["comments"],
style: GoogleFonts.poppins(fontSize: 11),
),
),
),
],
),
? Row(
children: [
Expanded(
flex: 2,
child: Text(
"Special Request",
style: GoogleFonts.poppins(fontSize: 11),
),
)
: Column(
children: [
_buildRow(
"Special Request:",
getRequestValue(item["special_request"]?.toString()),
),
SizedBox(width: 10),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
),
Expanded(
flex: 3,
child: Text(
" Comments",
style: GoogleFonts.poppins(fontSize: 11),
),
),
],
)
// : SizedBox.shrink(),
// isDesktop
// ? Row(
// children: [
// Expanded(
// flex: 2,
// child: Text(
// getRequestValue(
// item["special_request"]?.toString(),
// ),
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// Expanded(
// flex: 3,
// child: Text(
// item["comments"],
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// ],
// )
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
),
// Column(
// children: [
// _buildRow(
// "Special Request:",
// getRequestValue(item["special_request"]?.toString()),
// ),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
],
),
),
@ -306,34 +335,34 @@ class MiscellaneousListWidget extends StatelessWidget {
children: [
Expanded(
child:
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle: TextStyle(
color: Colors.black,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle: TextStyle(
color: Colors.black,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
overflow: TextOverflow.ellipsis,
),
)
: Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
],
);
@ -365,95 +394,95 @@ class MiscellaneousListWidget extends StatelessWidget {
SizedBox(width: 8),
Expanded(
child:
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle: TextStyle(
color: Colors.black,
fontSize: 12,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
overflow: TextOverflow.ellipsis,
),
)
: Text(value),
exceedsLimit
? Tooltip(
message: wrapText(value, 50),
decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6),
),
textStyle: TextStyle(
color: Colors.black,
fontSize: 12,
), // Tooltip text color
padding: EdgeInsets.all(8),
preferBelow: false,
child: Text(
value.substring(0, limit) + "...",
overflow: TextOverflow.ellipsis,
),
)
: Text(value),
),
],
);
}
//
// Widget _buildData(BuildContext context) {
// return Container(
// width: MediaQuery.of(context).size.width,
// child: DataTable(
// border: TableBorder(
// bottom: BorderSide(color: Colors.black12),
// horizontalInside: BorderSide(color: Colors.black12),
// ),
// columns: const [
// DataColumn(label: Text('Special Request')),
// DataColumn(label: Text('Comments')),
// DataColumn(label: Text('Actions')),
// ],
// rows: _buildDataRows(),
// ),
// );
// }
//
// List<DataRow> _buildDataRows() {
// List<dynamic> purposeList = apiData?['miscellaneous_special_request'] ?? [];
//
// String getRequestValue(String? specialRequestKey) {
// if (specialRequestKey == null) return "N/A";
// return purposeList
// .firstWhere(
// (element) =>
// element["dropdown_key"].toString() == specialRequestKey,
// orElse: () => {"dropdown_value": "N/A"},
// )["dropdown_value"]
// .toString();
// }
//
// List<Map<String, dynamic>> filteredList =
// miscellaneousList.where((item) => item["is_active"] == "1").toList();
//
// return filteredList.asMap().entries.map((entry) {
// Map<String, dynamic> item = entry.value;
//
// return DataRow(cells: [
// DataCell(Text(getRequestValue(item["special_request"]?.toString()))),
// DataCell(Text(item["comments"] ?? "N/A")),
// DataCell(Row(
// children: [
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/edit.png',
// width: 20, height: 15),
// ),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/delete.png',
// width: 20, height: 15),
// ),
// IconButton(
// icon: Icon(Icons.keyboard_arrow_down_outlined,
// size: 28, color: Color(0xFF475569)),
// onPressed: () {
// // Expand logic (optional)
// },
// ),
// ],
// )),
// ]);
// }).toList();
// }
}
//
// Widget _buildData(BuildContext context) {
// return Container(
// width: MediaQuery.of(context).size.width,
// child: DataTable(
// border: TableBorder(
// bottom: BorderSide(color: Colors.black12),
// horizontalInside: BorderSide(color: Colors.black12),
// ),
// columns: const [
// DataColumn(label: Text('Special Request')),
// DataColumn(label: Text('Comments')),
// DataColumn(label: Text('Actions')),
// ],
// rows: _buildDataRows(),
// ),
// );
// }
//
// List<DataRow> _buildDataRows() {
// List<dynamic> purposeList = apiData?['miscellaneous_special_request'] ?? [];
//
// String getRequestValue(String? specialRequestKey) {
// if (specialRequestKey == null) return "N/A";
// return purposeList
// .firstWhere(
// (element) =>
// element["dropdown_key"].toString() == specialRequestKey,
// orElse: () => {"dropdown_value": "N/A"},
// )["dropdown_value"]
// .toString();
// }
//
// List<Map<String, dynamic>> filteredList =
// miscellaneousList.where((item) => item["is_active"] == "1").toList();
//
// return filteredList.asMap().entries.map((entry) {
// Map<String, dynamic> item = entry.value;
//
// return DataRow(cells: [
// DataCell(Text(getRequestValue(item["special_request"]?.toString()))),
// DataCell(Text(item["comments"] ?? "N/A")),
// DataCell(Row(
// children: [
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/edit.png',
// width: 20, height: 15),
// ),
// SizedBox(width: 10),
// GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/delete.png',
// width: 20, height: 15),
// ),
// IconButton(
// icon: Icon(Icons.keyboard_arrow_down_outlined,
// size: 28, color: Color(0xFF475569)),
// onPressed: () {
// // Expand logic (optional)
// },
// ),
// ],
// )),
// ]);
// }).toList();
// }
}

View File

@ -36,6 +36,14 @@ class TaxiListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && taxiList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion(
cursor:
isViewMode
@ -248,6 +256,7 @@ class TaxiListWidget extends StatelessWidget {
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
),
),
Spacer(),
@ -259,6 +268,7 @@ class TaxiListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
),
),
),
@ -271,6 +281,7 @@ class TaxiListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
@ -358,22 +369,72 @@ class TaxiListWidget extends StatelessWidget {
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow("City:", item["destination_city"]),
SizedBox(width: 10),
_buildRow("Pickup:", item["location_of_pickup"]!),
SizedBox(width: 10),
_buildDateTimeRow(
"Date:",
formatDate(item["date"]!),
formatTime(item["time"]!),
),
_buildRow("TaxiFor:", item["car_required_for"]!),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
),
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// First row: City & Location
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoColumn("City", item["destination_city"] ?? "N/A"),
_infoColumn("Location", item["location_of_pickup"] ?? "N/A",alignEnd: true),
],
),
const SizedBox(height: 16),
// Second row: Date & Time
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoColumn("Date", "${formatDate(item["date"]!)}" ?? "N/A"),
_infoColumn("Time", "${formatTime(item["time"]!)}" ?? "N/A",alignEnd: true),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
// Comment box
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)else const Text( "N/A", style: TextStyle(fontSize: 12), ),
] )
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow("City:", item["destination_city"]),
// SizedBox(width: 10),
// _buildRow("Pickup:", item["location_of_pickup"]!),
// SizedBox(width: 10),
// _buildDateTimeRow(
// "Date:",
// formatDate(item["date"]!),
// formatTime(item["time"]!),
// ),
// _buildRow("TaxiFor:", item["car_required_for"]!),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
],
),
),
@ -501,4 +562,30 @@ class TaxiListWidget extends StatelessWidget {
],
);
}
Widget _infoColumn(String label, String value, {bool alignEnd = false}) {
return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
);
}
}

View File

@ -109,6 +109,14 @@ class _TrainListWidgetState extends State<TrainListWidget> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop))
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion(
cursor:
widget.isViewMode
@ -335,6 +343,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
),
),
Spacer(),
@ -346,6 +355,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
),
),
),
@ -358,6 +368,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
@ -528,23 +539,74 @@ class _TrainListWidgetState extends State<TrainListWidget> {
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow(
"Class:",
getRequestForTrainClass(item["class"]!.toString()),
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// First row: City & Location
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoColumn("Class", getRequestForTrainClass(item["class"]!.toString()) ?? "N/A"),
_infoColumn("From", item["from_station"]! ?? "N/A"),
_infoColumn("To", item["to_station"]! ?? "N/A",alignEnd: true),
],
),
const SizedBox(height: 16),
// Second row: Date & Time
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoColumn("Date", "${formatDate(item["date"]!)}" ?? "N/A"),
_infoColumn("Time", "${formatTime(item["time"]!)}" ?? "N/A",alignEnd: true),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
_buildRow("From:", item["from_station"]!),
_buildRow("To:", item["to_station"]!),
_buildDateTimeRow(
"Date:",
formatDate(item["date"]!),
formatTime(item["time"]!),
),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
),
),
const SizedBox(height: 8),
// Comment box
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)else const Text( "N/A", style: TextStyle(fontSize: 12), ),
] )
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow(
// "Class:",
// getRequestForTrainClass(item["class"]!.toString()),
// ),
// _buildRow("From:", item["from_station"]!),
// _buildRow("To:", item["to_station"]!),
// _buildDateTimeRow(
// "Date:",
// formatDate(item["date"]!),
// formatTime(item["time"]!),
// ),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
],
),
),
@ -659,6 +721,31 @@ class _TrainListWidgetState extends State<TrainListWidget> {
);
}
Widget _infoColumn(String label, String value, {bool alignEnd = false}) {
return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
);
}
Widget _buildDateTimeRow(String title, String date, String time) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -37,6 +37,14 @@ class VisaListWidget extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if ((!isDesktop) && visaList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
@ -58,11 +66,11 @@ class VisaListWidget extends StatelessWidget {
// style: TextStyle(fontSize: 13),
// ),
// SizedBox(width: 8), // spacing between icon and text
Icon(
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
)
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
],
),
),
@ -296,6 +304,7 @@ class VisaListWidget extends StatelessWidget {
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
),
),
Spacer(),
@ -307,6 +316,7 @@ class VisaListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
color: Color(0xFF114D8B),
),
),
),
@ -319,6 +329,7 @@ class VisaListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
@ -411,24 +422,68 @@ class VisaListWidget extends StatelessWidget {
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRow(
"VisaType:",
getRequestForVisa(
item["type_of_visa"]!.toString())),
SizedBox(height: 6),
_buildRow(
"Country:",
getRequestForCountry(
item["country_code"]!.toString())),
SizedBox(height: 6),
_buildRow("StartDate:", item["start_date"]!),
SizedBox(height: 6),
_buildRow("Comments:", item["comments"] ?? "N/A"),
],
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top Row (Country, Currency, Total)
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
Wrap(
spacing: 20, // horizontal space between items
runSpacing: 10, // vertical space between rows
children: [
_infoBlock("Visa Type", getRequestForCountry(item["country_code"]!.toString()) ?? "N/A"),
_infoBlock("Country", getRequestForCountry(item["country_code"]!.toString()) ?? "N/A"),
_infoBlock("Start Date", formatDate(item["start_date"]!) ?? "N/A"),
],
),
const SizedBox(height: 16),
// Comment label
Text(
"Comment",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFF7098DD), width: 1),
borderRadius: BorderRadius.circular(6),
),
child: Text(
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)
else
const Text( "N/A", style: TextStyle(fontSize: 12), ),
],
),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _buildRow(
// "VisaType:",
// getRequestForVisa(
// item["type_of_visa"]!.toString())),
// SizedBox(height: 6),
// _buildRow(
// "Country:",
// getRequestForCountry(
// item["country_code"]!.toString())),
// SizedBox(height: 6),
// _buildRow("StartDate:", item["start_date"]!),
// SizedBox(height: 6),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
],
),
),
@ -487,6 +542,34 @@ class VisaListWidget extends StatelessWidget {
);
}
Widget _infoBlock(String label, String value) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 4),
Text(
value,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
),
),
],
),
),
);
}
Widget _buildRow(String title, String value) {
// Define character limits based on title
Map<String, int> limits = {

View File

@ -72,17 +72,22 @@ class _ListPlansState extends State<ListPlans> {
print(roleUser);
if (roleUser == "User") {
print("user");
// Push a dummy state so back button triggers popstate instead of navigating
final prefs = await SharedPreferences.getInstance();
final String? msUserStr = prefs.getString('is_microsoft_user');
final bool msUser = msUserStr?.toLowerCase() == 'true';
print("msUser - $msUser");
html.window.history.pushState(null, '', html.window.location.href);
_popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) {
_showBackConfirmationDialog();
}
if(!msUser){
_popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) {
_showBackConfirmationDialog();
}
// Re-push to prevent leaving
html.window.history.pushState(null, '', html.window.location.href);
});
// Re-push to prevent leaving
html.window.history.pushState(null, '', html.window.location.href);
});
}
}
}
@ -955,7 +960,11 @@ class _ListPlansState extends State<ListPlans> {
builder: (context, constraints) {
double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox(
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child:ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth),
child: DataTable(
dividerThickness: 0.5,
@ -1361,7 +1370,7 @@ class _ListPlansState extends State<ListPlans> {
);
}).toList(),
),
);
)));
},
);
@ -1859,7 +1868,7 @@ class _ListPlansState extends State<ListPlans> {
CrossAxisAlignment.end,
children: [
Column(
Flexible( child:Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
@ -1881,7 +1890,7 @@ class _ListPlansState extends State<ListPlans> {
),
),
],
),
),),
Column(
mainAxisAlignment:
MainAxisAlignment.end,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
String? userId;
String? orgId;
String? roleId;
String? userIdApi;
bool isCheckingToken = false;
@ -677,6 +678,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> initializeData() async {
token = await getToken();
userId = await getUserId();
roleId = await getRoleId();
if (token == null || userId == null) {
print("Token or USerId missing");
@ -706,6 +708,19 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return null;
}
Future<String?> getRoleId() async {
final prefs = await SharedPreferences.getInstance();
final userData = prefs.getString('user_data');
if (userData != null) {
final decodedData = jsonDecode(userData);
// Return the user_id from the decoded data
return decodedData['role_id']?.toString();
}
return null;
}
@override
void dispose() {
// Dispose all controllers to prevent memory leaks
@ -1313,7 +1328,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("✅ User submitted successfully!");
print("📨 Response: ${response.body}");
context.go('/listUser');
if(roleId == "4"){ context.go('/listPlan'); }
else{ context.go('/listUser'); }
} else {
print("❌ Submission failed. Status: ${response.statusCode}");
print("📨 Body: ${response.body}");

View File

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
// import 'package:flutter/rendering.dart';
import 'dart:html' as html;
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
import 'package:frontend/services/apiService.dart';
@ -15,6 +15,7 @@ import 'package:flutter_quill/flutter_quill.dart';
import 'package:frontend/routes/custom_router.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Screens/myTemplates/templateTest.dart';
import 'package:fluttertoast/fluttertoast.dart';
class MyApp extends StatefulWidget {
const MyApp({super.key});
@ -27,12 +28,14 @@ class _MyAppState extends State<MyApp> {
final ApiService apiService = ApiService();
String? _authCode;
String? userRole;
bool _isAuthRedirect = false;
bool _isAuthRedirect = false; // Only true for Microsoft redirect
bool _isloading = false;
@override
void initState() {
super.initState();
SemanticsBinding.instance
.ensureSemantics(); // Safe here -only for testing uncomment, Otherwise Email Template wont allow to type
// SemanticsBinding.instance
// .ensureSemantics(); // Safe here -only for testing uncomment, Otherwise Email Template wont allow to type
if (kIsWeb) {
final uri = Uri.parse(html.window.location.href);
print("URI - $uri");
@ -51,38 +54,41 @@ class _MyAppState extends State<MyApp> {
print("query: $query");
final queryParams = Uri.splitQueryString(query);
print("query: $query");
print("queryParams: $queryParams");
final authCode = queryParams['code'];
if (fragmentPath == '/authredirection' && authCode != null) {
// _authCode = uri.queryParameters['code'];
_authCode = queryParams['code'];
// _isAuthRedirect = true;
html.window.console.log("Auth code detected: $_authCode");
// print(">>> _isAuthRedirect: $_isAuthRedirect");
print(">>> Auth code found at startup: $_authCode");
WidgetsBinding.instance.addPostFrameCallback((_) {
handleTokenUsingMS(_authCode);
setState(() {
_isAuthRedirect = true; // Show loading screen ONLY for MS login
});
} else {
print("🔍 Auth code detected at startup: $authCode");
// Immediately begin token handling
// WidgetsBinding.instance.addPostFrameCallback((_) {
// handleTokenUsingMS(authCode);
// });
handleTokenUsingMS(authCode).then((_) {
// 🔥 No URL cleanup leave it as is
setState(() {
_isAuthRedirect = false;
});
});
html.window.console.log("Auth code detected: $authCode");
}else {
html.window.console.log("No auth code found or wrong path.");
}
}
}
Future<void> handleTokenUsingMS(String? authCode) async {
// Note : Doing any change means just refer on login_widget.dart file - _login function. 24july2025
Future<void> handleTokenUsingMS(String authCode) async {
print("handleTokenUsingMS- $authCode");
if (authCode == null) return;
// final url =
// 'http://localhost:40617/tstat/auth/verifyMSAuthUser?code=$authCode';
final url = '$apiUrl/auth/verifyMSAuthUser?code=$authCode';
print("url- $url");
try {
// final url = 'http://localhost:43627/tstat/auth/verifyMSAuthUser?code=$authCode';
final url = '$apiUrl/auth/verifyMSAuthUser?code=$authCode';
print("Microsoft BE URL - $url");
final response = await http.get(
Uri.parse(url),
headers: {'Content-Type': 'application/json'},
@ -90,44 +96,69 @@ class _MyAppState extends State<MyApp> {
if (response.statusCode == 200) {
final responseBody = json.decode(response.body);
final MS_Token = responseBody['token'];
print("MS_Token - $MS_Token");
final token = responseBody['token'];
print("Microsoft_Token - $token");
setState(() {
_isloading = true;
});
if (MS_Token != null && MS_Token != '') {
if (token != null && token.isNotEmpty) {
print('Microsoft - Token Available');
await storeUserDetails(MS_Token);
final prefs = await SharedPreferences.getInstance();
await prefs.setString('is_microsoft_user', 'true');
await storeUserDetails(token);
setState(() {
_isloading = false;
});
if(_isloading){ const CircularProgressIndicator(); }
final userData = prefs.getString('user_data');
print("MS Userdata - $userData");
final orgDataString = prefs.getString('org_data');
print("MS orgdata - $orgDataString");
print("userRole - $userRole");
if (orgDataString != null && userData != null){
Fluttertoast.showToast(
msg: "You're in!",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16,
webBgColor: "linear-gradient(to right, #28a745, #28a745)",
);
if (userRole == "Travel Agent") {
router.go('/listTravelAgentPlan');
} else if (userRole == "Org Admin" || userRole == "Travel Admin") {
router.go('/listAllPlan');
} else {
router.go('/listPlan');
print("Microsoft User Logged In Refer the Role - $userRole");
// Navigate based on role
if (userRole == "Travel Agent") {
router.go('/listTravelAgentPlan');
} else if (userRole == "Org Admin" || userRole == "Travel Admin") {
router.go('/StatusDashboard');
} else {
router.go('/listPlan');
}
}
} else {
throw Exception('Token not found in response.');
throw Exception('Token missing in response.');
}
} else {
// Handle 400/401/500 etc.
String errorMsg;
try {
final decoded = json.decode(response.body);
errorMsg = decoded['message'] ?? 'Unknown error';
} catch (_) {
errorMsg = response.body; // fallback to plain text
}
print("Error response: $errorMsg");
throw Exception("Authentication failed: $errorMsg");
final error = json.decode(response.body)['message'] ?? 'Auth failed';
throw Exception(error);
}
} catch (e, stack) {
print("Caught error: $e");
} catch (e) {
Fluttertoast.showToast(
msg: "Login Failed: $e",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16,
webBgColor: "linear-gradient(to right, #dc1c13, #dc1c13)",
);
router.go('/');
}
}
// Note : Doing any change means just refer on login_widget.dart file - storeUserDetails function. 24july2025
Future<void> storeUserDetails(String token) async {
try {
final parts = token.split('.');
@ -141,10 +172,7 @@ class _MyAppState extends State<MyApp> {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('auth_token', token);
await prefs.setString(
'user_data',
jsonEncode(userData),
); // Store full user data
await prefs.setString('user_data', jsonEncode(userData)); // Store full user data
if (userData != null) {
final pref = await SharedPreferences.getInstance();
@ -153,19 +181,31 @@ class _MyAppState extends State<MyApp> {
userRole = userData['role'];
print("userData - $userData");
print("userData11 - ${userData['role']}");
print("userData12 - $userRole");
print("MicroSoft UserData RAW - $userData");
print("MicroSoft UserData ROLE RAW - ${userData['role']}");
print("MicroSoft UserData ROLE FECTHED - $userRole");
}
apiService.getOrganizationData();
print("MicroSoft Started");
await apiService.getOrganizationData();
print("MicroSoft end");
} catch (e) {
print('Error decoding token: $e');
print('Error decoding token MS: $e');
router.go('/');
}
}
@override
Widget build(BuildContext context) {
if (_isAuthRedirect) {
return const MaterialApp(
home: Scaffold(
body: Center(child: CircularProgressIndicator()),
),
);
}
return MaterialApp.router(
title: 'Trip Approval Tool',
debugShowCheckedModeBanner: false,

View File

@ -1,5 +1,19 @@
//api url
// const String apiUrl = 'http://localhost/tstat_be';
// const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be';
const String apiUrl =
'http://apitest.tripapprovaltool.com/tstat_be'; // look at this
const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be';
// const String apiUrl = 'https://apitest.tripapprovaltool.com/tstat_be';
/** Note : Adfactor UAT BE URL
* File : web/index.html - change below
* <base href="/tstat/"> replaced to <base href="/adfactor/"> **/
// const String apiUrl = 'https://uat.tripapprovaltool.com/adfactor_be';
/** Note : Aujas UAT BE URL
* File : web/index.html - change below
* <base href="/tstat/"> replaced to <base href="/aujas/"> **/
// const String apiUrl = 'https://uat.tripapprovaltool.com/aujas_be';
/** Note : Aujas Live BE URL
* File : web/index.html - change below
* <base href="/tstat/"> replaced to <base href="/aujas/"> **/
// const String apiUrl = 'https://tripapprovaltool.com/aujas_be' ;

View File

@ -15,7 +15,7 @@ import 'package:shared_preferences/shared_preferences.dart';
class ApiService {
Future<void> getOrganizationData() async {
try {
print("getUpdatedServices");
print("ORG getUpdatedServices");
final result = await fetchOrganization();
print("UUPdatedServices - $result");