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

View File

@ -798,7 +798,12 @@ class _ListAllPlansState extends State<ListAllPlans> {
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,
@ -811,8 +816,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
columns: [
DataColumn(
label: Expanded(
child: Text(
label: Text(
'S.NO',
style: GoogleFonts.poppins(
fontSize: 13,
@ -820,7 +824,6 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
),
),
),
DataColumn(
label: Text(
@ -930,11 +933,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true, // Allows wrapping
overflow:
TextOverflow
.visible, // Ensures full display
maxLines: null,
softWrap: true,
overflow: TextOverflow.ellipsis,
),
),
DataCell(
@ -1164,7 +1164,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
);
}).toList(),
),
);
),
));
},
);
@ -1256,12 +1257,6 @@ class _ListAllPlansState extends State<ListAllPlans> {
fontWeight:
FontWeight.w500,
),
softWrap:
true, // Allows wrapping
overflow:
TextOverflow
.visible, // Ensures full display
maxLines: null,
),
],
),
@ -1438,7 +1433,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
CrossAxisAlignment.end,
children: [
Column(
Flexible( child:Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
@ -1451,6 +1446,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
fontSize: 10,
color: Colors.black87,
),
// overflow: TextOverflow.ellipsis,
// maxLines: 2,
),
// Text(
// // plan.userName.isNotEmpty
@ -1472,7 +1469,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
),
],
),
),),
Column(
mainAxisAlignment:
MainAxisAlignment.end,

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,14 +491,17 @@ 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),
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(),
@ -508,9 +511,12 @@ class StatusDashboardState extends State<StatusDashboard> {
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 5),
const SizedBox(height: 6),
Text(
label,
maxLines: 2,
overflow: TextOverflow.ellipsis,
softWrap: true,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: isDesktop ? 12 : 11,
@ -519,6 +525,7 @@ class StatusDashboardState extends State<StatusDashboard> {
),
],
),
),
);
}

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(
SizedBox(height: 4),
Text(
value,
style: TextStyle(fontSize: 12),
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(
:
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"]!),
// 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",
),
_buildRow("Comments:", item["comments"] ?? "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
// 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
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(
child: Icon(
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
),
],
color: const Color(0xFF114D8B),
),
),
)
: SizedBox.shrink(),
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,
),
),
),
)
],
),
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,
),
_buildKeyValueRow(
"Sector",
"$fromcity ($fromcode), $fromairport$tocity ($tocode), $toairport",
),
_buildKeyValueRow(
"Date",
formatDate(trip["date"] ?? ""),
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,
),
),
],
),
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,
),
),
_buildKeyValueRow(
"Time",
formatTime(trip["time"] ?? ""),
),
],
),
),
);
}).toList(),
],
),

View File

@ -39,73 +39,24 @@ 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,
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
// ],
// if ((!isDesktop) && forexList.isNotEmpty)
// Text(
// " ",
// style: const TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// ),
// ),
),
// 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
//
// child: GestureDetector(
// onTap: isViewMode
// ? null
// : () {
// print("New data");
@ -115,6 +66,11 @@ class ForexListWidget extends StatelessWidget {
// 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,
@ -123,9 +79,61 @@ class ForexListWidget extends StatelessWidget {
// ],
// ),
// ),
// // 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(
): 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"),
// 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(
Widget _infoBlock(String label, String value) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
label,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
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: GoogleFonts.poppins(
fontSize: 12,
),
overflow: TextOverflow.ellipsis),
)
: Text(
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 = {
// // "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,51 +34,23 @@ 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: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// if ((!isDesktop) && insuranceList.isNotEmpty)
// Text(
// "Add New",
// style: TextStyle(fontSize: 13),
// " ",
// style: const TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// ),
// 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
// MouseRegion(
// cursor: isViewMode
// ? SystemMouseCursors.forbidden
// : SystemMouseCursors.click,
// child: GestureDetector(
// onTap: isViewMode
// ? null
// : () {
// print("New data");
@ -88,17 +60,53 @@ class InsuranceListWidget extends StatelessWidget {
// mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely
// children: [
// Icon(
// Icons.add_circle_sharp,
// size: 30,
// color: Color(0xFF114D8B),
// )
// // 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(
:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
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"),
// 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,16 +26,22 @@ 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
@ -58,24 +64,29 @@ class MiscellaneousListWidget extends StatelessWidget {
// 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,
// ),
// ),
// ),
],
),
),
@ -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,45 +211,37 @@ class MiscellaneousListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
color: Colors.red,
),
),
),
],
),
// Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 10),
Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 4),
isDesktop
? Row(
children: [
// Expanded(
// flex: 2,
// child: Text(
// "Special Request",
// style: GoogleFonts.poppins(fontSize: 11),
// ),
// ),
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,
),
style: GoogleFonts.poppins(fontSize: 11),
),
),
],
)
: SizedBox.shrink(),
SizedBox(height: 4),
isDesktop
? Container(
// color: Color(0xFFE8F0FC),
color: Colors.white,
child: Expanded(
child: Row(
children: [
// : SizedBox.shrink(),
// isDesktop
// ? Row(
// children: [
// Expanded(
// flex: 2,
// child: Text(
@ -251,32 +254,58 @@ class MiscellaneousListWidget extends StatelessWidget {
// ),
// ),
// ),
// 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: MediaQuery.of(context).size.width * 0.6,
// padding: EdgeInsets.all(16),
// color: Color(0xFFE8F0FC),
child: Expanded(
// flex: 1,
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"],
style: GoogleFonts.poppins(fontSize: 11),
),
),
),
],
),
item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
)
: Column(
children: [
_buildRow(
"Special Request:",
getRequestValue(item["special_request"]?.toString()),
),
SizedBox(width: 10),
_buildRow("Comments:", item["comments"] ?? "N/A"),
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"),
// ],
// ),
],
),
),

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(
:
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"),
// 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(
:
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"),
// 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,
),
),
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(
:
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"),
// 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,9 +72,13 @@ 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);
if(!msUser){
_popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) {
_showBackConfirmationDialog();
@ -85,6 +89,7 @@ class _ListPlansState extends State<ListPlans> {
});
}
}
}
@override
void dispose() {
@ -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

View File

@ -50,10 +50,12 @@ class _PolicyState extends State<Policy> {
Color? layoutColor;
Color? bodyColor;
late String policyType = "domestic";
String selectedServiceDBValue = '1';
// String selectedServiceDBValue = '1';
List<int> serviceDBValueList = [];
ValueNotifier<String> selectedServiceIndex = ValueNotifier("1");
ValueNotifier<String> selectedServicePriorityIndex = ValueNotifier("1");
String selectedService = "train";
ValueNotifier<String> selectedServiceDBValue = ValueNotifier("0");
String? selectedService;
// ValueNotifier<String> selectedService = ValueNotifier("Train");
bool isViewMode = false;
bool isDisable = false;
@ -101,6 +103,7 @@ class _PolicyState extends State<Policy> {
});
}).toList();
Map<String, dynamic> data = {
"name": _policyController.text,
"domestic": SelectedDomestic,
@ -152,7 +155,6 @@ class _PolicyState extends State<Policy> {
// }
// });
}
void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() {
setState(() {
@ -160,7 +162,6 @@ class _PolicyState extends State<Policy> {
});
});
}
void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token
@ -175,19 +176,33 @@ class _PolicyState extends State<Policy> {
try {
loadinitializeData();
updateSelectedServices();
await updateSelectedServices();
updateData();
loadInitialData();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.policy != null) {
final details = List<Map<String, dynamic>>.from(
widget.policy!['policy_details'],
);
policyCriteriaKey.currentState?.loadPolicyDetails(details);
policyCriteriaKey.currentState?.fetchTrainFlightClass();
}
});
// if (widget.policy != null) {
// print("185");
// final details = List<Map<String, dynamic>>.from(
// widget.policy!['policy_details'],
// );
// policyCriteriaKey.currentState?.loadPolicyDetails(details);
//
// policyCriteriaKey.currentState?.fetchTrainFlightClass();
// }
} catch (e) {
print("group : $e");
}
@ -261,24 +276,32 @@ class _PolicyState extends State<Policy> {
}
Future<void> updateSelectedServices() async {
print("started");
await loadAllServices();
await loadOrgSelectedAlServices();
print("III-end");
final selectedIds =
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
if (widget.policy != null) {
print("inside if");
print(widget.policy);
final details = List<Map<String, dynamic>>.from(
widget.policy!['policy_details'],
);
print("****details-$details");
print(
"UUFiltered Selected Services - ${widget.policy!['services_ids']} ",
);
// pr int("UUFiltered Selected Services - $details");
final exisitingService = List<Map<String, dynamic>>.from(
jsonDecode(widget.policy!['services_ids']),
);
print("exisitingService ${exisitingService}");
final filtered =
selectedAllServices!
exisitingService!
.where(
(service) =>
selectedIds.contains(service['service_id'].toString()),
@ -288,18 +311,35 @@ class _PolicyState extends State<Policy> {
setState(() {
ServicesChoosed = filtered;
});
print("298 ServicesChoosed ${ServicesChoosed}");
print("Filtered Selected Services ChooesedIpfa1: $ServicesChoosed");
if (ServicesChoosed!.isNotEmpty) {
String firstServiceName = ServicesChoosed?.first['name'];
print("✅ First service name selected for filter: $firstServiceName");
selectedService = firstServiceName;
// services = ServicesChoosed!
// .map((service) => service['name'].toString())
// .toList();
}
print("Filtered Selected Services ChooesedIpfa1: $ServicesChoosed");
ServicesChoosed!.sort(
(a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0),
);
String firstServiceName = ServicesChoosed?.first['name'];
String firstServiceId = ServicesChoosed?.first['service_id'];
print("✅ 306 First service name selected for filter: $firstServiceName - $firstServiceId");
selectedService = firstServiceName;
if (selectedServiceDBValue.value == "0") {
setState(() {
selectedServiceDBValue.value = firstServiceId.toString();
});
}
List<int> serviceDBvalue = ServicesChoosed!
.map((item) => int.parse(item['service_id'].toString()))
.toList();
serviceDBValueList = serviceDBvalue;
}
print(widget.policy);
// updateData();
if (widget.policy != null && widget.policy!['services_ids'] != null) {
final decoded = jsonDecode(widget.policy!['services_ids']);
@ -317,10 +357,14 @@ class _PolicyState extends State<Policy> {
});
print("✅ Loaded services from policy (decoded): $services");
}
print("Filtered Selected Services Added to Policy: $ServicesChoosed");
} else {
}
else {
final filtered =
selectedAllServices!
.where(
@ -354,15 +398,33 @@ class _PolicyState extends State<Policy> {
print("Filtered Selected Services Chooesed1: $ServicesChoosed");
if (ServicesChoosed!.isNotEmpty) {
String firstServiceName = ServicesChoosed?.first['name'];
print("✅ First service name selected for filter: $firstServiceName");
selectedService = firstServiceName;
policyCriteriaKey.currentState?.fetchTrainFlightClass();
ServicesChoosed!.sort(
(a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0),
);
String firstServiceName = ServicesChoosed?.first['name'];
String firstServiceId = ServicesChoosed?.first['service_id'];
print("✅ 363 First service name selected for filter: $firstServiceName - $firstServiceId");
selectedService = firstServiceName;
if (selectedServiceDBValue.value == "0") {
setState(() {
selectedServiceDBValue.value = firstServiceId.toString();
});
}
List<int> serviceDBvalue = ServicesChoosed!
.map((item) => int.parse(item['service_id'].toString()))
.toList();
serviceDBValueList = serviceDBvalue;
}
}
}
void updateData() {
print("updateData");
// if (widget.policy != null && selectedService != null && selectedServiceDBValue.value != "0") {
if (widget.policy != null) {
setState(() {
selectedPolicyId = widget.policy?["policy_id"] ?? "";
@ -380,6 +442,7 @@ class _PolicyState extends State<Policy> {
policy_details = List<Map<String, dynamic>>.from(
widget.policy?["policy_details"] ?? [],
);
// print("policy_details ${policy_details}");
});
}
}
@ -462,6 +525,7 @@ class _PolicyState extends State<Policy> {
});
}
bool isValidData(Map<String, dynamic> data) {
errorMessages.clear(); // Reset previous errors
@ -1149,11 +1213,13 @@ class _PolicyState extends State<Policy> {
List<String> services =
ServicesChoosed!.map((service) => service['name'].toString()).toList();
List<String> serviceDBvalue =
ServicesChoosed!
.map((service) => service['service_id'].toString())
// List<int> serviceDBvalue =
// ServicesChoosed!.map((service) => int.parse(service['service_id'].toString())).toList();
List<int> serviceDBvalue = ServicesChoosed!
.map((item) => int.parse(item['service_id'].toString()))
.toList();
print("1093");
print(services);
print(serviceDBvalue);
@ -1165,9 +1231,12 @@ class _PolicyState extends State<Policy> {
direction: Axis.horizontal,
children:
services.asMap().entries.map((entry) {
int index = entry.key + 1;
print("1182 ${entry}");
int i = entry.key;
int index = i + 1;
String service = entry.value;
String serviceId = index.toString();
int serviceId = serviceDBvalue[i];
bool isSelected =
selectedServiceIndex.value == index.toString();
@ -1184,30 +1253,26 @@ class _PolicyState extends State<Policy> {
// max((MediaQuery.of(context).size.height * 0.09), 10)
child: GestureDetector(
onTap: () {
print("Selected Services - $service - $index");
print("1201 Selected Services - $service - Tab Index - $index Service Id- $serviceId");
setState(() {
selectedServiceIndex.value = index.toString();
selectedServiceDBValue = serviceDBvalue[entry.key];
selectedServiceDBValue.value = serviceId.toString();
selectedService = service;
print(
" selectedServiceIndex.value - ${selectedServiceIndex.value}",
);
print(
" selectedServiceDBValue.value - ${selectedServiceDBValue}",
);
// policyCriteriaKey.currentState?.fieldForPolicy();
// policyCriteriaKey.currentState
// ?.addOrUpdatePolicy(selectedServiceIndex.value);
print("policyselectedService - $selectedService");
if (selectedService == "Flight" ||
selectedService == "Train" ||
selectedService == "Accomodation") {
selectedService == "Train" || selectedService == "Accomodation") {
showClass = true;
showCost = false;
int serviceCode = selectedService == "Flight" ? 1 : 2;
// int serviceCode = selectedService == "Flight" ? 1 : 2;
print("policyselectedService1 - $selectedService");
policyCriteriaKey.currentState
?.fetchTrainFlightClass();
@ -1387,19 +1452,24 @@ class _PolicyState extends State<Policy> {
}
Widget _buildPolicyCategory(bool isDesktop) {
print("1408 $selectedServiceIndex");
print("1409 $selectedService");
print("1410 ${selectedServiceDBValue.value}");
return Container(
margin: isDesktop ? EdgeInsets.all(5) : null,
// color: Colors.brown.shade100,
// child: Text("data"),
// color: Colors.white60,
child: PolicyCriteria(
child: (selectedService != null && selectedServiceDBValue.value != "0")
? PolicyCriteria(
key: policyCriteriaKey,
isDesktop: isDesktop,
isClass: showClass,
isCost: showCost,
selectedTabNotifier: selectedServiceIndex,
selectedService: selectedService,
selectedServiceDBValue: selectedServiceDBValue,
selectedIdNotifier: selectedServiceDBValue,
selectedService: selectedService!,
serviceDBValueList: serviceDBValueList, // 👈 Pass the array here
userId: userId,
onPolicyDataChanged: (List<Map<String, dynamic>>? policyData) {
print("🟢 policyData received from child: $policyData");
@ -1411,7 +1481,7 @@ class _PolicyState extends State<Policy> {
});
});
},
),
) : const Center(child: CircularProgressIndicator()),
);
}

View File

@ -14,11 +14,12 @@ import '../../widgets/custom_user_form.dart';
class PolicyCriteria extends StatefulWidget {
bool isDesktop;
String selectedService;
String selectedServiceDBValue;
final ValueNotifier<String> selectedTabNotifier;
final ValueNotifier<String> selectedIdNotifier;
String? userId;
bool isClass = true;
bool isCost = true;
final List<int> serviceDBValueList;
final Function(List<Map<String, dynamic>>?) onPolicyDataChanged;
@ -27,18 +28,19 @@ class PolicyCriteria extends StatefulWidget {
required this.isDesktop,
required this.selectedService,
required this.selectedTabNotifier,
required this.selectedServiceDBValue,
required this.selectedIdNotifier,
required this.userId,
required this.isClass,
required this.isCost,
required this.onPolicyDataChanged,
required this.serviceDBValueList,
});
@override
PolicyCriteriaState createState() => PolicyCriteriaState();
}
class PolicyCriteriaState extends State<PolicyCriteria> {
String? ServiceId = "1";
String? ServiceId;// = "1";
String? ServiceIndxId = "1";
String? orgId;
@ -101,19 +103,32 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
@override
void initState() {
super.initState();
fetchTrainFlightClass();
print("whole value here - ${widget.serviceDBValueList}");
print(widget.serviceDBValueList);
fieldForPolicy();
widget.selectedIdNotifier.addListener(() {
setState(() {
ServiceId = widget.selectedIdNotifier.value ?? "1";
print("new :) ${widget.selectedIdNotifier.value}");
print("ServiceIndxId changed: $ServiceId");
});
});
widget.selectedTabNotifier.addListener(() {
print("selectedTab changed: ${widget.selectedTabNotifier.value}");
setState(() {
ServiceIndxId = widget.selectedTabNotifier.value ?? "1";
// ServiceId = widget.selectedIdNotifier.value ?? "1";
print("ServiceIndxId changed: $ServiceIndxId");
});
fieldForPolicy();
fetchTrainFlightClass();
// fetchTrainFlightClass(); // old here
});
}
@ -146,6 +161,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// Step 3: Loop through all service definitions
for (var service in services) {
String id = service['service_id'].toString();
print("164 service == $id");
// Skip if already present
if (existingServiceIds!.contains(id)) continue;
@ -200,6 +216,8 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// To set the data (update)
void loadPolicyDetails(List<Map<String, dynamic>> details) {
print("loadPolicyDetails");
for (var item in details) {
final serviceId = item['service_id'].toString();
@ -321,14 +339,12 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
[a1, a2, a3].where((a) => a != null).length > 0 &&
[a1, a2, a3].where((a) => a == null).length > 0;
bool allExceptionalActionsNull =
ae1 == null && ae2 == null && ae3 == null && ae4 == null;
bool allExceptionalActionsNull = ae1 == null && ae2 == null && ae3 == null && ae4 == null;
bool someExceptionalActionsMissing =
[ae1, ae2, ae3, ae4].where((a) => a != null).length > 0 &&
[ae1, ae2, ae3, ae4].where((a) => a == null).length > 0;
bool allAmendActionsNull =
aa1 == null && aa2 == null && aa3 == null && aa4 == null;
bool allAmendActionsNull = aa1 == null && aa2 == null && aa3 == null && aa4 == null;
bool someAmendActionsMissing =
[aa1, aa2, aa3, aa4].where((a) => a != null).length > 0 &&
[aa1, aa2, aa3, aa4].where((a) => a == null).length > 0;
@ -439,6 +455,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// }
Future<void> fetchTrainFlightClass() async {
print("ftech api");
try {
final data = await apiService.fetchMasterDropdown();
@ -460,7 +477,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
void fieldForPolicy() {
print("fieldForPolicy - ${widget.selectedTabNotifier.value}");
print("POlicyCheck - $policyData");
// Save current input to policyData before switching
if (ServiceId != null) {
print("Calling addOrUpdatePolicy");
@ -470,12 +487,25 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
}
setState(() {
// ServiceId = widget.selectedTabNotifier.value ?? "1";
ServiceId = widget.selectedServiceDBValue;
print("ServiceId");
print(ServiceId);
// Initialize controllers and variables if not present (Controller Creation)
final String tabIndexStr = widget.selectedTabNotifier.value;
print(" fns - $ServiceId");
// Safely convert tab index to int
final int? tabIndex = int.tryParse(tabIndexStr);
print(" tb inx - $tabIndex");
print(" db - ${widget.serviceDBValueList.length}");
print(" db list - ${widget.serviceDBValueList}");
if (tabIndex != null && tabIndex >= 0 && tabIndex <= widget.serviceDBValueList.length) {
ServiceId = widget.serviceDBValueList[tabIndex-1].toString();
print('✅ 484 Selected ServiceId: $ServiceId');
}
else {
print('❌ Invalid tab index or out of range');
}
print("502 ServiceId $ServiceId");
// Initialize controllers and variables if not present
costController.putIfAbsent(ServiceId!, () => TextEditingController());
classAction.putIfAbsent((widget.selectedServiceDBValue), () => "1");
classAction.putIfAbsent((ServiceId!), () => "1");
// classController.putIfAbsent(ServiceId!, () => TextEditingController());
FirstApproverAction.putIfAbsent(ServiceId!, () => "None");
@ -1238,10 +1268,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
children: [
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -1387,10 +1414,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
),
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -1540,10 +1564,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
),
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -1694,10 +1715,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
),
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -1942,10 +1960,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
children: [
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -2091,10 +2106,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
),
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -2244,10 +2256,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
),
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -2398,10 +2407,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
),
Container(
// padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 4.0,
),
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -2580,19 +2586,21 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// : (apiDataForClass?['train_class'] ?? []);
// }
if (ServiceIndxId != null) {
switch (ServiceIndxId) {
if (ServiceId != null) {
// ServiceId = '1';
print("sid $ServiceId");
switch (ServiceId) {
case "1":
textLabel = "Class";
purposeList = apiDataForClass?['flight_class'] ?? [];
break;
case "2":
case "5":
textLabel = "Category";
purposeList = apiDataForClass?['hotel_class'] ?? [];
break;
case "9":
case "2":
textLabel = "Class";
purposeList = apiDataForClass?['train_class'] ?? [];
break;
@ -2606,8 +2614,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
print("CLASS-ServiceId- $ServiceId");
print("CLASS-ServiceIndxId- $ServiceIndxId");
print("CLASS-purposeList - $purposeList");
print("CLASS-DB Service Id - ${widget.selectedServiceDBValue}");
print("CLASS-Action - ${classAction[widget.selectedServiceDBValue]}");
print("CLASS-Action - ${classAction[ServiceId]}");
// Sort by dropdown_key
purposeList.sort((a, b) {
@ -2626,6 +2633,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
@ -2651,14 +2659,13 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// }
// 1. First, when dropdownItems are ready, assign default value:
if ((widget.selectedServiceDBValue) != null &&
classAction[(widget.selectedServiceDBValue)] == null &&
if ((ServiceId) != null &&
classAction[ServiceId] == null &&
dropdownItems.isNotEmpty) {
// Important to wrap inside setState if async
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
classAction[(widget.selectedServiceDBValue)] =
dropdownItems.first.value!;
classAction[ServiceId!] = dropdownItems.first.value!;
});
});
}
@ -2718,18 +2725,13 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
height: 40,
width: double.infinity,
child:
(widget.selectedServiceDBValue) != null &&
(isLoading || dropdownItems.isEmpty)
(ServiceId!) != null && (isLoading || dropdownItems.isEmpty)
? const Center(child: CircularProgressIndicator())
: DropdownSearch<Map<String, dynamic>>(
key:
classAction[(widget.selectedServiceDBValue)] ==
null
classAction[(ServiceId!)] == null
? UniqueKey()
: ValueKey(
classAction[(widget
.selectedServiceDBValue)],
),
: ValueKey(classAction[(ServiceId!)]),
items: purposeList.cast<Map<String, dynamic>>(),
// selectedItem: purposeList.firstWhere(
@ -2737,13 +2739,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// orElse: () => {},
// ),
selectedItem:
classAction[(widget.selectedServiceDBValue)] !=
null
classAction[(ServiceId!)] != null
? purposeList.firstWhere(
(item) =>
item['dropdown_key'] ==
classAction[(widget
.selectedServiceDBValue)],
classAction[(ServiceId!)],
orElse: () => {},
)
: null,
@ -2806,11 +2806,10 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) async {
setState(() {
classAction[(widget
.selectedServiceDBValue)] =
classAction[(ServiceId!)] =
newValue?['dropdown_key'];
print(
"Selected Purpose: ${classAction[(widget.selectedServiceDBValue)]}",
"Selected Purpose: ${classAction[(ServiceId!)]}",
);
});
}

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
});
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)",
);
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('/listAllPlan');
router.go('/StatusDashboard');
} else {
router.go('/listPlan');
}
} else {
throw Exception('Token not found 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
throw Exception('Token missing in response.');
}
print("Error response: $errorMsg");
throw Exception("Authentication failed: $errorMsg");
} else {
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");