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) { builder: (context, constraints) {
double minWidth = isDesktop ? constraints.maxWidth : 1300; double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child:
ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
child: DataTable( child: DataTable(
dividerThickness: 0.5, dividerThickness: 0.5,
@ -811,8 +816,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
), ),
columns: [ columns: [
DataColumn( DataColumn(
label: Expanded( label: Text(
child: Text(
'S.NO', 'S.NO',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
@ -820,7 +824,6 @@ class _ListAllPlansState extends State<ListAllPlans> {
), ),
), ),
), ),
),
DataColumn( DataColumn(
label: Text( label: Text(
@ -930,11 +933,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
), ),
softWrap: true, // Allows wrapping softWrap: true,
overflow: overflow: TextOverflow.ellipsis,
TextOverflow
.visible, // Ensures full display
maxLines: null,
), ),
), ),
DataCell( DataCell(
@ -1164,7 +1164,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
); );
}).toList(), }).toList(),
), ),
); ),
));
}, },
); );
@ -1256,12 +1257,6 @@ class _ListAllPlansState extends State<ListAllPlans> {
fontWeight: fontWeight:
FontWeight.w500, 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, CrossAxisAlignment.end,
children: [ children: [
Column( Flexible( child:Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
@ -1451,6 +1446,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
fontSize: 10, fontSize: 10,
color: Colors.black87, color: Colors.black87,
), ),
// overflow: TextOverflow.ellipsis,
// maxLines: 2,
), ),
// Text( // Text(
// // plan.userName.isNotEmpty // // plan.userName.isNotEmpty
@ -1472,7 +1469,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
), ),
), ),
], ],
), ),),
Column( Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.end, 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) { builder: (context, constraints) {
double minWidth = isDesktop ? constraints.maxWidth : 1300; double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child:
ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
child: DataTable( child: DataTable(
dividerThickness: 0.5, dividerThickness: 0.5,
@ -1416,7 +1421,7 @@ class _ApprovalListState extends State<ApprovalList> {
); );
}).toList(), }).toList(),
), ),
); )));
}, },
); );
@ -1647,7 +1652,7 @@ class _ApprovalListState extends State<ApprovalList> {
CrossAxisAlignment.end, CrossAxisAlignment.end,
children: [ children: [
Column( Flexible( child:Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
@ -1666,7 +1671,7 @@ class _ApprovalListState extends State<ApprovalList> {
), ),
), ),
], ],
), ),),
Column( Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.end, 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) { Widget statusCard(String label, int count, bool isDesktop) {
return Container( return SizedBox(
width: isDesktop ? 120 : double.infinity, 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( decoration: BoxDecoration(
color: const Color(0xFFEAF3FB), color: const Color(0xFFEAF3FB),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, // vertically center everything
children: [ children: [
Text( Text(
count.toString(), count.toString(),
@ -508,9 +511,12 @@ class StatusDashboardState extends State<StatusDashboard> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
const SizedBox(height: 5), const SizedBox(height: 6),
Text( Text(
label, label,
maxLines: 2,
overflow: TextOverflow.ellipsis,
softWrap: true,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: isDesktop ? 12 : 11, 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), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldItnerarySubWrapper(
isFocused: _destinationFocused, isFocused: _destinationFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: width:
isDesktop isDesktop
? MediaQuery.of(context).size.width * 0.34 ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, : null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
@ -1164,7 +1164,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
_checkInTimeFocusNode.requestFocus(); _checkInTimeFocusNode.requestFocus();
_checkInTimeController.text = ""; // _checkInTimeController.text = ""; // pavithra told me. here client reported the issues here thats why.
_selectCheckInTime(context); _selectCheckInTime(context);
}, },
child: AbsorbPointer( child: AbsorbPointer(
@ -1326,13 +1326,14 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
), ),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( // CustomTextFieldWrapper
CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop, isDesktop: isDesktop,
width: width:
isDesktop isDesktop
? MediaQuery.of(context).size.width * 0.34 ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, : null, // MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(

View File

@ -647,7 +647,7 @@ class _BusScreenState extends State<BusScreen> {
), ),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : null, 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), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldForexWrapper(
isFocused: isFocused:
focusStates["_comments"] ?? false, // Dropdown doesn't use focus focusStates["_comments"] ?? false, // Dropdown doesn't use focus
isDesktop: isDesktop, isDesktop: isDesktop,
@ -2301,7 +2301,7 @@ class _ForexScreenState extends State<ForexScreen> {
), ),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldForexWrapper(
isFocused: isFocused:
focusStates["_deliveryLocation"] ?? focusStates["_deliveryLocation"] ??
false, // Dropdown doesn't use focus false, // Dropdown doesn't use focus
@ -2344,7 +2344,7 @@ class _ForexScreenState extends State<ForexScreen> {
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: isDesktop ? MainAxisAlignment.center : MainAxisAlignment.start,
children: [ children: [
Container( Container(
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,

View File

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

View File

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

View File

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

View File

@ -456,7 +456,7 @@ class _TrainScreenState extends State<TrainScreen> {
dropdownItems.isNotEmpty ? dropdownItems.first.value : null; dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [ return [
CustomTextFieldWrapper( CustomTextFieldItnerarySubWrapper(
isFocused: _trainNoFocused, isFocused: _trainNoFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,
@ -653,7 +653,8 @@ class _TrainScreenState extends State<TrainScreen> {
// ), // ),
// ), // ),
// ), // ),
CustomTextFieldWrapper( // CustomTextFieldWrapper
CustomTextFieldItnerarySubWrapper(
isFocused: _typeOfClassFocus, isFocused: _typeOfClassFocus,
padding: const EdgeInsets.symmetric(horizontal: 0), padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: isDesktop, isDesktop: isDesktop,
@ -1332,7 +1333,7 @@ class _TrainScreenState extends State<TrainScreen> {
), ),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldItnerarySubWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null, 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, isFocused: _isHotelNameFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
padding: const EdgeInsets.symmetric(horizontal: 0), padding: const EdgeInsets.symmetric(horizontal: 0),
width: width:
isDesktop isDesktop
? MediaQuery.of(context).size.width * 0.34 ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, : null,//MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: Focus( child: Focus(
@ -586,7 +586,7 @@ class _VisaScreenState extends State<VisaScreen> {
vertical: 6, vertical: 6,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(right: 4.0), padding: const EdgeInsets.only(right: 1.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -927,7 +927,7 @@ class _VisaScreenState extends State<VisaScreen> {
width: width:
isDesktop isDesktop
? MediaQuery.of(context).size.width * 0.34 ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, : null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(

View File

@ -34,10 +34,15 @@ class AccomodationListWidget extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// Text( if ((!isDesktop) && accommodationList.isNotEmpty)
// "Accomodation Booking List", Text(
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), " ",
// ), style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion( MouseRegion(
cursor: isViewMode cursor: isViewMode
? SystemMouseCursors.forbidden ? SystemMouseCursors.forbidden
@ -64,6 +69,24 @@ class AccomodationListWidget extends StatelessWidget {
size: 30, size: 30,
color: Color(0xFF114D8B), 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( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: Color(0xFF575A74)), color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),)
), ),
Spacer(), Spacer(),
GestureDetector( GestureDetector(
@ -251,6 +274,7 @@ class AccomodationListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), ),
@ -263,6 +287,7 @@ class AccomodationListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/delete.png',
width: 20, width: 20,
height: 15, height: 15,
color: Colors.red,
), ),
), ),
), ),
@ -356,21 +381,82 @@ class AccomodationListWidget extends StatelessWidget {
: Column( : Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildRow("City:", item["destination_city"]), Wrap(
SizedBox(width: 10), spacing: 20, // horizontal space between items
SizedBox(width: 10), runSpacing: 10, // vertical space between rows
_buildDateTimeRow( children: [
"Check-in:", _buildInfoColumn("City", item["destination_city"]),
formatDate(item["checkin_date"]!), _buildInfoColumn("Check (In)", "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}"),
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), const SizedBox(height: 10),
_buildRow( const Text(
"Date(out):", formatDate(item["checkout_date"]!)), "Comment",
SizedBox(width: 10), style: TextStyle(fontWeight: FontWeight.w500),
_buildRow("Comments:", item["comments"] ?? "N/A"), ),
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) { // Helper widget
// Define character limits based on title Widget _buildInfoColumn(String label, String value) {
Map<String, int> limits = { return Column(
// "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, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
title, label,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
), ),
), ),
SizedBox(width: 8), SizedBox(height: 4),
Expanded( Text(
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, value,
style: TextStyle(fontSize: 12), style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black87,
), ),
), ),
], ],
); );
} }
Widget _buildDateTimeRow(String title, String date, String time) { // Widget _buildRow(String title, String value) {
return Row( // // Define character limits based on title
crossAxisAlignment: CrossAxisAlignment.start, // Map<String, int> limits = {
children: [ // // "Special Request:": 30,
Text( // "Comments:": 10,
title, // // Add more keys and limits if needed
style: GoogleFonts.poppins( // };
fontSize: 12, //
fontWeight: FontWeight.w600, // int limit = limits[title] ?? 50; // Default limit if title not found
), // bool exceedsLimit = value.length > limit;
), //
SizedBox(width: 8), // String wrapText(String text, int maxLineLength) {
Expanded( // final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)');
child: Text( // return pattern.allMatches(text).map((m) => m.group(0)!).join('\n');
"$date, $time", // }
style: GoogleFonts.poppins( //
fontSize: 12, // 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( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if ((!isDesktop) && busList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion( MouseRegion(
cursor: isViewMode cursor: isViewMode
? SystemMouseCursors.forbidden ? SystemMouseCursors.forbidden
@ -65,6 +74,24 @@ class BusListWidget extends StatelessWidget {
size: 30, size: 30,
color: Color(0xFF114D8B), 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', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
// color: Color(0xFF114D8B),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
), ),
), ),
), ),
@ -242,6 +271,7 @@ class BusListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/delete.png',
width: 20, width: 20,
height: 15, height: 15,
color: Colors.red,
), ),
), ),
), ),
@ -314,21 +344,70 @@ class BusListWidget extends StatelessWidget {
), ),
], ],
) )
: Column( :
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildRow("From:", item["from"]), // Top Row (Country, Currency, Total)
SizedBox(width: 10), Wrap(
_buildRow("To:", item["to"]!), spacing: 20, // horizontal space between items
SizedBox(width: 10), runSpacing: 10, // vertical space between rows
_buildDateTimeRow( // Row(
"Date:", // mainAxisAlignment: MainAxisAlignment.spaceBetween,
formatDate(item["date"]!), children: [
formatTime(item["time"]!), _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) { Widget _buildComments(String title, String value) {
// Define character limits based on title // Define character limits based on title
Map<String, int> limits = { 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( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Container( child: Container(
@ -115,58 +175,67 @@ class _FlightListWidgetState extends State<FlightListWidget> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// Header with title and button // Row: Title (mobile only) + Add Button (conditional)
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// Text( // Title (optional on desktop or mobile)
// "Flight Booking List", if ((!isDesktop) && widget.flightList.isNotEmpty)
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), Text(
// ), " ",
widget.flightList.isNotEmpty style: const TextStyle(
? MouseRegion( fontSize: 18,
cursor: fontWeight: FontWeight.bold,
widget.isViewMode ),
),
// Right side: either "Add" icon or nothing
if (widget.flightList.isNotEmpty)
MouseRegion(
cursor: widget.isViewMode
? SystemMouseCursors.forbidden ? SystemMouseCursors.forbidden
: SystemMouseCursors.click, : SystemMouseCursors.click,
child: GestureDetector( child: GestureDetector(
onTap: onTap: widget.isViewMode
widget.isViewMode
? null ? null
: () { : () {
widget.onAddNew("Flight", true); widget.onAddNew("Flight", true);
// checkClass();
print("New data"); print("New data");
}, },
child: Row( child: Icon(
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, Icons.add_circle_sharp,
size: 30, 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), const SizedBox(height: 16),
// Scroll behavior based on device // Actual flight data UI
_buildData(context, isDesktop), _buildData(context, isDesktop),
], ],
), ),
), ),
); );
} }
Widget _buildData(BuildContext context, bool isDesktop) { Widget _buildData(BuildContext context, bool isDesktop) {
@ -313,6 +382,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),
), ),
), ),
Spacer(), Spacer(),
@ -324,6 +394,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), ),
@ -336,6 +407,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/delete.png',
width: 20, width: 20,
height: 15, height: 15,
color: Colors.red,
), ),
), ),
), ),
@ -559,40 +631,175 @@ class _FlightListWidgetState extends State<FlightListWidget> {
final tocity = tocityMatch?.group(1) ?? ''; final tocity = tocityMatch?.group(1) ?? '';
final tocode = tocityMatch?.group(2) ?? ''; 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( return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0), padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Container( 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( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildKeyValueRow( Wrap(
"Class", crossAxisAlignment: WrapCrossAlignment.center,
getRequestForClass(trip["class"].toString()) ?? spacing: 4,
"N/A", 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",
), ),
Text(
_buildKeyValueRow( fromcode,
"Date", style: const TextStyle(
formatDate(trip["date"] ?? ""), 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(), }).toList(),
], ],
), ),

View File

@ -39,73 +39,24 @@ class ForexListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// Header with title and button // Header with title and button
Row( // Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MouseRegion(
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: isViewMode
? null
: () {
print("New data");
onAddNew("Forex", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text(
// "Add New",
// style: TextStyle(fontSize: 13),
// ),
// SizedBox(width: 8), // spacing between icon and text
Icon(
Icons.add_circle_sharp,
size: 30,
color: Color(0xFF114D8B),
)
],
),
),
// onPressed: isViewMode
// ? null
// : () {
// print("New data");
//
// },
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [ // children: [
// Icon( // if ((!isDesktop) && forexList.isNotEmpty)
// Icons.add_circle_sharp, // Text(
// size: 30, // " ",
// color: Color(0xFF114D8B), // style: const TextStyle(
// ) // fontSize: 18,
// ], // fontWeight: FontWeight.bold,
// ),
// ), // ),
),
// MouseRegion( // MouseRegion(
// cursor: isViewMode // cursor: isViewMode
// ? SystemMouseCursors.forbidden // ? SystemMouseCursors.forbidden
// : SystemMouseCursors.click, // : SystemMouseCursors.click,
// child: ElevatedButton( //
// style: ElevatedButton.styleFrom( // child: GestureDetector(
// backgroundColor: Color(0xFF114D8B), // onTap: isViewMode
// 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 // ? null
// : () { // : () {
// print("New data"); // print("New data");
@ -115,6 +66,11 @@ class ForexListWidget extends StatelessWidget {
// mainAxisSize: // mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely // MainAxisSize.min, // Ensures content fits nicely
// children: [ // children: [
// // Text(
// // "Add New",
// // style: TextStyle(fontSize: 13),
// // ),
// // SizedBox(width: 8), // spacing between icon and text
// Icon( // Icon(
// Icons.add_circle_sharp, // Icons.add_circle_sharp,
// size: 30, // 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), const SizedBox(height: 16),
// Scroll behavior based on device // Scroll behavior based on device
@ -275,21 +283,24 @@ class ForexListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
// color: Color(0xFF114D8B),
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
), ),
), ),
), ),
SizedBox(width: 10), // SizedBox(width: 10),
GestureDetector( // GestureDetector(
onTap: () => onDeleteForex(item), // onTap: () => onDeleteForex(item),
child: Tooltip( // child: Tooltip(
message: 'Delete Forex Details', // message: 'Delete Forex Details',
child: Image.asset( // child: Image.asset(
'assets/images/IconsImg/delete.png', // 'assets/images/IconsImg/delete.png',
width: 20, // width: 20,
height: 15, // height: 15,
), // color: Colors.red,
), // ),
), // ),
// ),
item['forex_id'] != null item['forex_id'] != null
? IconButton( ? IconButton(
icon: Icon(Icons.download, icon: Icon(Icons.download,
@ -495,30 +506,84 @@ class ForexListWidget extends StatelessWidget {
"Comments:", item["comments"] ?? "N/A"), "Comments:", item["comments"] ?? "N/A"),
), ),
], ],
) ): Column(
: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildRow( // Top Row (Country, Currency, Total)
"Currency:", Wrap(
item["currency"], spacing: 20, // horizontal space between items
), runSpacing: 10, // vertical space between rows
// SizedBox(height: 6), // Row(
_buildRow( // mainAxisAlignment: MainAxisAlignment.spaceBetween,
"Duration:", children: [
item["duration"], _infoBlock("Country code", item["country_code"] ?? "N/A"),
), _infoBlock("Currency", item["currency"] ?? "N/A"),
// SizedBox(height: 6), _infoBlock("Total Amount", item["total_amount"]?.toString() ?? "0"),
_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"),
], ],
), ),
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) { Widget _infoBlock(String label, String value) {
// Define character limits based on title return Expanded(
Map<String, int> limits = { child: Padding(
// "Special Request:": 30, padding: const EdgeInsets.only(right: 12),
"Comments:": 10, child: Column(
// 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, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
title, label,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.bold,
color: Colors.black87,
), ),
), ),
SizedBox(width: 8), const SizedBox(height: 4),
Expanded( Text(
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, value,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, 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, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// Header with title and button // Header with title and button
Row( // Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ // children: [
MouseRegion( // if ((!isDesktop) && insuranceList.isNotEmpty)
cursor: isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector(
onTap: isViewMode
? null
: () {
print("New data");
onAddNew("Insurance", true);
},
child: Row(
mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely
children: [
// Text( // 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: // MouseRegion(
// EdgeInsets.symmetric(horizontal: 20, vertical: 12), // cursor: isViewMode
// ), // ? SystemMouseCursors.forbidden
// onPressed: isViewMode // : SystemMouseCursors.click,
// child: GestureDetector(
// onTap: isViewMode
// ? null // ? null
// : () { // : () {
// print("New data"); // print("New data");
@ -88,17 +60,53 @@ class InsuranceListWidget extends StatelessWidget {
// mainAxisSize: // mainAxisSize:
// MainAxisSize.min, // Ensures content fits nicely // MainAxisSize.min, // Ensures content fits nicely
// children: [ // children: [
// Icon( // // Text(
// Icons.add_circle_sharp, // // "Add New",
// size: 30, // // style: TextStyle(fontSize: 13),
// color: Color(0xFF114D8B), // // ),
// ) // // 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), const SizedBox(height: 16),
// Scroll behavior based on device // Scroll behavior based on device
@ -197,6 +205,7 @@ class InsuranceListWidget extends StatelessWidget {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
), ),
), ),
Spacer(), Spacer(),
@ -208,21 +217,23 @@ class InsuranceListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), ),
SizedBox(width: 10), // SizedBox(width: 10),
GestureDetector( // GestureDetector(
onTap: () => onDeleteInsurance(item), // onTap: () => onDeleteInsurance(item),
child: Tooltip( // child: Tooltip(
message: 'Delete Insurance Details', // message: 'Delete Insurance Details',
child: Image.asset( // child: Image.asset(
'assets/images/IconsImg/delete.png', // 'assets/images/IconsImg/delete.png',
width: 20, // width: 20,
height: 15, // height: 15,
), // color: Colors.red,
), // ),
), // ),
// ),
], ],
), ),
SizedBox(height: 4), SizedBox(height: 4),
@ -293,21 +304,65 @@ class InsuranceListWidget extends StatelessWidget {
), ),
], ],
) )
: Column( :
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildRow( // Top Row (Country, Currency, Total)
"InsuranceType:", // Row(
getRequestForInsuranceType( // mainAxisAlignment: MainAxisAlignment.spaceBetween,
item["type_of_insurance"]!.toString())), Wrap(
SizedBox(width: 10), spacing: 20, // horizontal space between items
_buildRow( runSpacing: 10, // vertical space between rows
"StartDate:", formatDate(item["start_date"]!)), children: [
SizedBox(width: 10), _infoBlock("Insurance Type", getRequestForInsuranceType(item["type_of_insurance"]!.toString()) ?? "N/A"),
_buildRow("EndDate:", formatDate(item["end_date"])), _infoBlock("Start Date", formatDate(item["start_date"]!) ?? "N/A"),
SizedBox(width: 10), _infoBlock("End Date", formatDate(item["end_date"]) ?? "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(
// 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) { Widget _buildRow(String title, String value) {
// Define character limits based on title // Define character limits based on title
Map<String, int> limits = { Map<String, int> limits = {

View File

@ -26,16 +26,22 @@ class MiscellaneousListWidget extends StatelessWidget {
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Container( child: Container(
// color: Color(0xFFE8F0FC), margin: const EdgeInsets.only(top: 16.0),
margin: const EdgeInsets.only(top: 28.0),
padding: const EdgeInsets.all(10.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// Header with title and button // Header with title and button
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if ((!isDesktop) && miscellaneousList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion( MouseRegion(
cursor: cursor:
isViewMode isViewMode
@ -58,24 +64,29 @@ class MiscellaneousListWidget extends StatelessWidget {
// style: TextStyle(fontSize: 13), // style: TextStyle(fontSize: 13),
// ), // ),
// SizedBox(width: 8), // spacing between icon and text // SizedBox(width: 8), // spacing between icon and text
Container( Icon(
decoration: BoxDecoration( Icons.add_circle_sharp,
shape: BoxShape.circle, size: 30,
border: Border.all( color: Color(0xFF114D8B),
color: Color(0xFF114D8B), // Outline color
width: 2, // Outline thickness
),
),
height: 30,
width: 30,
child: Center(
child: Icon(
Icons.add,
size: 20,
color: Colors.black,
),
),
), ),
// 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()), getRequestValue(item["special_request"]?.toString()),
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Color(0xFF114D8B), fontWeight: FontWeight.w800,
fontWeight: FontWeight.w500,
), ),
), ),
Spacer(), Spacer(),
@ -187,6 +197,7 @@ class MiscellaneousListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), ),
@ -200,45 +211,37 @@ class MiscellaneousListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/delete.png',
width: 20, width: 20,
height: 15, height: 15,
color: Colors.red,
), ),
), ),
), ),
], ],
), ),
// Divider(color: Colors.blueGrey.shade50), Divider(color: Colors.blueGrey.shade50),
SizedBox(height: 10), SizedBox(height: 4),
isDesktop isDesktop
? Row( ? Row(
children: [ children: [
// Expanded( Expanded(
// flex: 2, flex: 2,
// child: Text( child: Text(
// "Special Request", "Special Request",
// style: GoogleFonts.poppins(fontSize: 11), style: GoogleFonts.poppins(fontSize: 11),
// ), ),
// ), ),
Expanded( Expanded(
flex: 3, flex: 3,
child: Text( child: Text(
"Comments", " Comments",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w600,
),
), ),
), ),
], ],
) )
: SizedBox.shrink(), // : SizedBox.shrink(),
SizedBox(height: 4), // isDesktop
isDesktop // ? Row(
? Container( // children: [
// color: Color(0xFFE8F0FC),
color: Colors.white,
child: Expanded(
child: Row(
children: [
// Expanded( // Expanded(
// flex: 2, // flex: 2,
// child: Text( // 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( Container(
// width: MediaQuery.of(context).size.width * 0.6, width: double.infinity,
// padding: EdgeInsets.all(16), padding: const EdgeInsets.all(12),
// color: Color(0xFFE8F0FC), decoration: BoxDecoration(
child: Expanded( border: Border.all(color: const Color(0xFF7098DD), width: 1),
// flex: 1, borderRadius: BorderRadius.circular(6),
),
child: Text( child: Text(
item["comments"], item["comments"] ?? "N/A",
style: GoogleFonts.poppins(fontSize: 11), style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87),
),
),
),
],
),
), ),
) )
: Column( else
children: [ const Text( "N/A", style: TextStyle(fontSize: 12), ),
_buildRow(
"Special Request:",
getRequestValue(item["special_request"]?.toString()),
),
SizedBox(width: 10),
_buildRow("Comments:", item["comments"] ?? "N/A"),
], ],
), ),
// Column(
// children: [
// _buildRow(
// "Special Request:",
// getRequestValue(item["special_request"]?.toString()),
// ),
// SizedBox(width: 10),
// _buildRow("Comments:", item["comments"] ?? "N/A"),
// ],
// ),
], ],
), ),
), ),
@ -389,71 +418,71 @@ class MiscellaneousListWidget extends StatelessWidget {
); );
} }
// //
// Widget _buildData(BuildContext context) { // Widget _buildData(BuildContext context) {
// return Container( // return Container(
// width: MediaQuery.of(context).size.width, // width: MediaQuery.of(context).size.width,
// child: DataTable( // child: DataTable(
// border: TableBorder( // border: TableBorder(
// bottom: BorderSide(color: Colors.black12), // bottom: BorderSide(color: Colors.black12),
// horizontalInside: BorderSide(color: Colors.black12), // horizontalInside: BorderSide(color: Colors.black12),
// ), // ),
// columns: const [ // columns: const [
// DataColumn(label: Text('Special Request')), // DataColumn(label: Text('Special Request')),
// DataColumn(label: Text('Comments')), // DataColumn(label: Text('Comments')),
// DataColumn(label: Text('Actions')), // DataColumn(label: Text('Actions')),
// ], // ],
// rows: _buildDataRows(), // rows: _buildDataRows(),
// ), // ),
// ); // );
// } // }
// //
// List<DataRow> _buildDataRows() { // List<DataRow> _buildDataRows() {
// List<dynamic> purposeList = apiData?['miscellaneous_special_request'] ?? []; // List<dynamic> purposeList = apiData?['miscellaneous_special_request'] ?? [];
// //
// String getRequestValue(String? specialRequestKey) { // String getRequestValue(String? specialRequestKey) {
// if (specialRequestKey == null) return "N/A"; // if (specialRequestKey == null) return "N/A";
// return purposeList // return purposeList
// .firstWhere( // .firstWhere(
// (element) => // (element) =>
// element["dropdown_key"].toString() == specialRequestKey, // element["dropdown_key"].toString() == specialRequestKey,
// orElse: () => {"dropdown_value": "N/A"}, // orElse: () => {"dropdown_value": "N/A"},
// )["dropdown_value"] // )["dropdown_value"]
// .toString(); // .toString();
// } // }
// //
// List<Map<String, dynamic>> filteredList = // List<Map<String, dynamic>> filteredList =
// miscellaneousList.where((item) => item["is_active"] == "1").toList(); // miscellaneousList.where((item) => item["is_active"] == "1").toList();
// //
// return filteredList.asMap().entries.map((entry) { // return filteredList.asMap().entries.map((entry) {
// Map<String, dynamic> item = entry.value; // Map<String, dynamic> item = entry.value;
// //
// return DataRow(cells: [ // return DataRow(cells: [
// DataCell(Text(getRequestValue(item["special_request"]?.toString()))), // DataCell(Text(getRequestValue(item["special_request"]?.toString()))),
// DataCell(Text(item["comments"] ?? "N/A")), // DataCell(Text(item["comments"] ?? "N/A")),
// DataCell(Row( // DataCell(Row(
// children: [ // children: [
// GestureDetector( // GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"), // onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/edit.png', // child: Image.asset('assets/images/IconsImg/edit.png',
// width: 20, height: 15), // width: 20, height: 15),
// ), // ),
// SizedBox(width: 10), // SizedBox(width: 10),
// GestureDetector( // GestureDetector(
// onTap: () => onOpen(true, item, "Miscellaneous"), // onTap: () => onOpen(true, item, "Miscellaneous"),
// child: Image.asset('assets/images/IconsImg/delete.png', // child: Image.asset('assets/images/IconsImg/delete.png',
// width: 20, height: 15), // width: 20, height: 15),
// ), // ),
// IconButton( // IconButton(
// icon: Icon(Icons.keyboard_arrow_down_outlined, // icon: Icon(Icons.keyboard_arrow_down_outlined,
// size: 28, color: Color(0xFF475569)), // size: 28, color: Color(0xFF475569)),
// onPressed: () { // onPressed: () {
// // Expand logic (optional) // // Expand logic (optional)
// }, // },
// ), // ),
// ], // ],
// )), // )),
// ]); // ]);
// }).toList(); // }).toList();
// } // }
} }

View File

@ -36,6 +36,14 @@ class TaxiListWidget extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if ((!isDesktop) && taxiList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion( MouseRegion(
cursor: cursor:
isViewMode isViewMode
@ -248,6 +256,7 @@ class TaxiListWidget extends StatelessWidget {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
), ),
), ),
Spacer(), Spacer(),
@ -259,6 +268,7 @@ class TaxiListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), ),
@ -271,6 +281,7 @@ class TaxiListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/delete.png',
width: 20, width: 20,
height: 15, height: 15,
color: Colors.red,
), ),
), ),
), ),
@ -358,22 +369,72 @@ class TaxiListWidget extends StatelessWidget {
), ),
], ],
) )
: Column( :
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildRow("City:", item["destination_city"]), // First row: City & Location
SizedBox(width: 10), Row(
_buildRow("Pickup:", item["location_of_pickup"]!), mainAxisAlignment: MainAxisAlignment.spaceBetween,
SizedBox(width: 10), children: [
_buildDateTimeRow( _infoColumn("City", item["destination_city"] ?? "N/A"),
"Date:", _infoColumn("Location", item["location_of_pickup"] ?? "N/A",alignEnd: true),
formatDate(item["date"]!),
formatTime(item["time"]!),
),
_buildRow("TaxiFor:", item["car_required_for"]!),
_buildRow("Comments:", item["comments"] ?? "N/A"),
], ],
), ),
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( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if ((!isDesktop))
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion( MouseRegion(
cursor: cursor:
widget.isViewMode widget.isViewMode
@ -335,6 +343,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
), ),
), ),
Spacer(), Spacer(),
@ -346,6 +355,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), ),
@ -358,6 +368,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/delete.png',
width: 20, width: 20,
height: 15, height: 15,
color: Colors.red,
), ),
), ),
), ),
@ -528,23 +539,74 @@ class _TrainListWidgetState extends State<TrainListWidget> {
), ),
], ],
) )
: Column( :
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildRow( // First row: City & Location
"Class:", Row(
getRequestForTrainClass(item["class"]!.toString()), mainAxisAlignment: MainAxisAlignment.spaceBetween,
), children: [
_buildRow("From:", item["from_station"]!), _infoColumn("Class", getRequestForTrainClass(item["class"]!.toString()) ?? "N/A"),
_buildRow("To:", item["to_station"]!), _infoColumn("From", item["from_station"]! ?? "N/A"),
_buildDateTimeRow( _infoColumn("To", item["to_station"]! ?? "N/A",alignEnd: true),
"Date:",
formatDate(item["date"]!),
formatTime(item["time"]!),
),
_buildRow("Comments:", item["comments"] ?? "N/A"),
], ],
), ),
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) { Widget _buildDateTimeRow(String title, String date, String time) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -37,6 +37,14 @@ class VisaListWidget extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if ((!isDesktop) && visaList.isNotEmpty)
Text(
" ",
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
MouseRegion( MouseRegion(
cursor: isViewMode cursor: isViewMode
? SystemMouseCursors.forbidden ? SystemMouseCursors.forbidden
@ -58,11 +66,11 @@ class VisaListWidget extends StatelessWidget {
// style: TextStyle(fontSize: 13), // style: TextStyle(fontSize: 13),
// ), // ),
// SizedBox(width: 8), // spacing between icon and text // SizedBox(width: 8), // spacing between icon and text
Icon( // Icon(
Icons.add_circle_sharp, // Icons.add_circle_sharp,
size: 30, // size: 30,
color: Color(0xFF114D8B), // color: Color(0xFF114D8B),
) // )
], ],
), ),
), ),
@ -296,6 +304,7 @@ class VisaListWidget extends StatelessWidget {
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74)
), ),
), ),
Spacer(), Spacer(),
@ -307,6 +316,7 @@ class VisaListWidget extends StatelessWidget {
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
height: 15, height: 15,
color: Color(0xFF114D8B),
), ),
), ),
), ),
@ -319,6 +329,7 @@ class VisaListWidget extends StatelessWidget {
'assets/images/IconsImg/delete.png', 'assets/images/IconsImg/delete.png',
width: 20, width: 20,
height: 15, height: 15,
color: Colors.red,
), ),
), ),
), ),
@ -411,24 +422,68 @@ class VisaListWidget extends StatelessWidget {
), ),
], ],
) )
: Column( :
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildRow( // Top Row (Country, Currency, Total)
"VisaType:", // Row(
getRequestForVisa( // mainAxisAlignment: MainAxisAlignment.spaceBetween,
item["type_of_visa"]!.toString())), Wrap(
SizedBox(height: 6), spacing: 20, // horizontal space between items
_buildRow( runSpacing: 10, // vertical space between rows
"Country:", children: [
getRequestForCountry( _infoBlock("Visa Type", getRequestForCountry(item["country_code"]!.toString()) ?? "N/A"),
item["country_code"]!.toString())), _infoBlock("Country", getRequestForCountry(item["country_code"]!.toString()) ?? "N/A"),
SizedBox(height: 6), _infoBlock("Start Date", formatDate(item["start_date"]!) ?? "N/A"),
_buildRow("StartDate:", item["start_date"]!),
SizedBox(height: 6),
_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(
// "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) { Widget _buildRow(String title, String value) {
// Define character limits based on title // Define character limits based on title
Map<String, int> limits = { Map<String, int> limits = {

View File

@ -72,9 +72,13 @@ class _ListPlansState extends State<ListPlans> {
print(roleUser); print(roleUser);
if (roleUser == "User") { if (roleUser == "User") {
print("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); html.window.history.pushState(null, '', html.window.location.href);
if(!msUser){
_popStateListener = html.window.onPopState.listen((event) { _popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) { if (!_dialogShown && mounted) {
_showBackConfirmationDialog(); _showBackConfirmationDialog();
@ -85,6 +89,7 @@ class _ListPlansState extends State<ListPlans> {
}); });
} }
} }
}
@override @override
void dispose() { void dispose() {
@ -955,7 +960,11 @@ class _ListPlansState extends State<ListPlans> {
builder: (context, constraints) { builder: (context, constraints) {
double minWidth = isDesktop ? constraints.maxWidth : 1300; double minWidth = isDesktop ? constraints.maxWidth : 1300;
return ConstrainedBox( return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child:ConstrainedBox(
constraints: BoxConstraints(minWidth: minWidth), constraints: BoxConstraints(minWidth: minWidth),
child: DataTable( child: DataTable(
dividerThickness: 0.5, dividerThickness: 0.5,
@ -1361,7 +1370,7 @@ class _ListPlansState extends State<ListPlans> {
); );
}).toList(), }).toList(),
), ),
); )));
}, },
); );
@ -1859,7 +1868,7 @@ class _ListPlansState extends State<ListPlans> {
CrossAxisAlignment.end, CrossAxisAlignment.end,
children: [ children: [
Column( Flexible( child:Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
@ -1881,7 +1890,7 @@ class _ListPlansState extends State<ListPlans> {
), ),
), ),
], ],
), ),),
Column( Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.end, 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? layoutColor;
Color? bodyColor; Color? bodyColor;
late String policyType = "domestic"; late String policyType = "domestic";
String selectedServiceDBValue = '1'; // String selectedServiceDBValue = '1';
List<int> serviceDBValueList = [];
ValueNotifier<String> selectedServiceIndex = ValueNotifier("1"); ValueNotifier<String> selectedServiceIndex = ValueNotifier("1");
ValueNotifier<String> selectedServicePriorityIndex = ValueNotifier("1"); ValueNotifier<String> selectedServicePriorityIndex = ValueNotifier("1");
String selectedService = "train"; ValueNotifier<String> selectedServiceDBValue = ValueNotifier("0");
String? selectedService;
// ValueNotifier<String> selectedService = ValueNotifier("Train"); // ValueNotifier<String> selectedService = ValueNotifier("Train");
bool isViewMode = false; bool isViewMode = false;
bool isDisable = false; bool isDisable = false;
@ -101,6 +103,7 @@ class _PolicyState extends State<Policy> {
}); });
}).toList(); }).toList();
Map<String, dynamic> data = { Map<String, dynamic> data = {
"name": _policyController.text, "name": _policyController.text,
"domestic": SelectedDomestic, "domestic": SelectedDomestic,
@ -152,7 +155,6 @@ class _PolicyState extends State<Policy> {
// } // }
// }); // });
} }
void _addFocusListener(FocusNode node, Function(bool) updateState) { void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() { node.addListener(() {
setState(() { setState(() {
@ -160,7 +162,6 @@ class _PolicyState extends State<Policy> {
}); });
}); });
} }
void _checkAuthAndLoadData() async { void _checkAuthAndLoadData() async {
final String? token = await getToken(); // Your async function to get token final String? token = await getToken(); // Your async function to get token
@ -175,19 +176,33 @@ class _PolicyState extends State<Policy> {
try { try {
loadinitializeData(); loadinitializeData();
updateSelectedServices(); await updateSelectedServices();
updateData(); updateData();
loadInitialData(); loadInitialData();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.policy != null) { if (widget.policy != null) {
final details = List<Map<String, dynamic>>.from( final details = List<Map<String, dynamic>>.from(
widget.policy!['policy_details'], widget.policy!['policy_details'],
); );
policyCriteriaKey.currentState?.loadPolicyDetails(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) { } catch (e) {
print("group : $e"); print("group : $e");
} }
@ -261,24 +276,32 @@ class _PolicyState extends State<Policy> {
} }
Future<void> updateSelectedServices() async { Future<void> updateSelectedServices() async {
print("started");
await loadAllServices(); await loadAllServices();
await loadOrgSelectedAlServices(); await loadOrgSelectedAlServices();
print("III-end");
final selectedIds = final selectedIds =
selectedOrgServiceIds.map((e) => e['service_id']).toSet(); selectedOrgServiceIds.map((e) => e['service_id']).toSet();
if (widget.policy != null) { if (widget.policy != null) {
print("inside if");
print(widget.policy);
final details = List<Map<String, dynamic>>.from( final details = List<Map<String, dynamic>>.from(
widget.policy!['policy_details'], widget.policy!['policy_details'],
); );
print("****details-$details");
print( print(
"UUFiltered Selected Services - ${widget.policy!['services_ids']} ", "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 = final filtered =
selectedAllServices! exisitingService!
.where( .where(
(service) => (service) =>
selectedIds.contains(service['service_id'].toString()), selectedIds.contains(service['service_id'].toString()),
@ -288,18 +311,35 @@ class _PolicyState extends State<Policy> {
setState(() { setState(() {
ServicesChoosed = filtered; ServicesChoosed = filtered;
}); });
print("298 ServicesChoosed ${ServicesChoosed}");
print("Filtered Selected Services ChooesedIpfa1: $ServicesChoosed");
if (ServicesChoosed!.isNotEmpty) { if (ServicesChoosed!.isNotEmpty) {
String firstServiceName = ServicesChoosed?.first['name']; print("Filtered Selected Services ChooesedIpfa1: $ServicesChoosed");
print("✅ First service name selected for filter: $firstServiceName");
selectedService = firstServiceName;
// services = ServicesChoosed!
// .map((service) => service['name'].toString())
// .toList();
}
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) { if (widget.policy != null && widget.policy!['services_ids'] != null) {
final decoded = jsonDecode(widget.policy!['services_ids']); final decoded = jsonDecode(widget.policy!['services_ids']);
@ -317,10 +357,14 @@ class _PolicyState extends State<Policy> {
}); });
print("✅ Loaded services from policy (decoded): $services"); print("✅ Loaded services from policy (decoded): $services");
} }
print("Filtered Selected Services Added to Policy: $ServicesChoosed"); print("Filtered Selected Services Added to Policy: $ServicesChoosed");
} else {
}
else {
final filtered = final filtered =
selectedAllServices! selectedAllServices!
.where( .where(
@ -354,15 +398,33 @@ class _PolicyState extends State<Policy> {
print("Filtered Selected Services Chooesed1: $ServicesChoosed"); print("Filtered Selected Services Chooesed1: $ServicesChoosed");
if (ServicesChoosed!.isNotEmpty) { if (ServicesChoosed!.isNotEmpty) {
String firstServiceName = ServicesChoosed?.first['name'];
print("✅ First service name selected for filter: $firstServiceName");
selectedService = firstServiceName;
policyCriteriaKey.currentState?.fetchTrainFlightClass(); 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() { void updateData() {
print("updateData");
// if (widget.policy != null && selectedService != null && selectedServiceDBValue.value != "0") {
if (widget.policy != null) { if (widget.policy != null) {
setState(() { setState(() {
selectedPolicyId = widget.policy?["policy_id"] ?? ""; selectedPolicyId = widget.policy?["policy_id"] ?? "";
@ -380,6 +442,7 @@ class _PolicyState extends State<Policy> {
policy_details = List<Map<String, dynamic>>.from( policy_details = List<Map<String, dynamic>>.from(
widget.policy?["policy_details"] ?? [], widget.policy?["policy_details"] ?? [],
); );
// print("policy_details ${policy_details}");
}); });
} }
} }
@ -462,6 +525,7 @@ class _PolicyState extends State<Policy> {
}); });
} }
bool isValidData(Map<String, dynamic> data) { bool isValidData(Map<String, dynamic> data) {
errorMessages.clear(); // Reset previous errors errorMessages.clear(); // Reset previous errors
@ -1149,11 +1213,13 @@ class _PolicyState extends State<Policy> {
List<String> services = List<String> services =
ServicesChoosed!.map((service) => service['name'].toString()).toList(); ServicesChoosed!.map((service) => service['name'].toString()).toList();
List<String> serviceDBvalue = // List<int> serviceDBvalue =
ServicesChoosed! // ServicesChoosed!.map((service) => int.parse(service['service_id'].toString())).toList();
.map((service) => service['service_id'].toString()) List<int> serviceDBvalue = ServicesChoosed!
.map((item) => int.parse(item['service_id'].toString()))
.toList(); .toList();
print("1093"); print("1093");
print(services); print(services);
print(serviceDBvalue); print(serviceDBvalue);
@ -1165,9 +1231,12 @@ class _PolicyState extends State<Policy> {
direction: Axis.horizontal, direction: Axis.horizontal,
children: children:
services.asMap().entries.map((entry) { 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 service = entry.value;
String serviceId = index.toString(); int serviceId = serviceDBvalue[i];
bool isSelected = bool isSelected =
selectedServiceIndex.value == index.toString(); selectedServiceIndex.value == index.toString();
@ -1184,30 +1253,26 @@ class _PolicyState extends State<Policy> {
// max((MediaQuery.of(context).size.height * 0.09), 10) // max((MediaQuery.of(context).size.height * 0.09), 10)
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
print("Selected Services - $service - $index"); print("1201 Selected Services - $service - Tab Index - $index Service Id- $serviceId");
setState(() { setState(() {
selectedServiceIndex.value = index.toString(); selectedServiceIndex.value = index.toString();
selectedServiceDBValue = serviceDBvalue[entry.key]; selectedServiceDBValue.value = serviceId.toString();
selectedService = service; selectedService = service;
print( print(
" selectedServiceIndex.value - ${selectedServiceIndex.value}", " selectedServiceIndex.value - ${selectedServiceIndex.value}",
); );
print(
" selectedServiceDBValue.value - ${selectedServiceDBValue}",
);
// policyCriteriaKey.currentState?.fieldForPolicy(); // policyCriteriaKey.currentState?.fieldForPolicy();
// policyCriteriaKey.currentState // policyCriteriaKey.currentState
// ?.addOrUpdatePolicy(selectedServiceIndex.value); // ?.addOrUpdatePolicy(selectedServiceIndex.value);
print("policyselectedService - $selectedService"); print("policyselectedService - $selectedService");
if (selectedService == "Flight" || if (selectedService == "Flight" ||
selectedService == "Train" || selectedService == "Train" || selectedService == "Accomodation") {
selectedService == "Accomodation") {
showClass = true; showClass = true;
showCost = false; showCost = false;
int serviceCode = selectedService == "Flight" ? 1 : 2; // int serviceCode = selectedService == "Flight" ? 1 : 2;
print("policyselectedService1 - $selectedService"); print("policyselectedService1 - $selectedService");
policyCriteriaKey.currentState policyCriteriaKey.currentState
?.fetchTrainFlightClass(); ?.fetchTrainFlightClass();
@ -1387,19 +1452,24 @@ class _PolicyState extends State<Policy> {
} }
Widget _buildPolicyCategory(bool isDesktop) { Widget _buildPolicyCategory(bool isDesktop) {
print("1408 $selectedServiceIndex");
print("1409 $selectedService");
print("1410 ${selectedServiceDBValue.value}");
return Container( return Container(
margin: isDesktop ? EdgeInsets.all(5) : null, margin: isDesktop ? EdgeInsets.all(5) : null,
// color: Colors.brown.shade100, // color: Colors.brown.shade100,
// child: Text("data"), // child: Text("data"),
// color: Colors.white60, // color: Colors.white60,
child: PolicyCriteria( child: (selectedService != null && selectedServiceDBValue.value != "0")
? PolicyCriteria(
key: policyCriteriaKey, key: policyCriteriaKey,
isDesktop: isDesktop, isDesktop: isDesktop,
isClass: showClass, isClass: showClass,
isCost: showCost, isCost: showCost,
selectedTabNotifier: selectedServiceIndex, selectedTabNotifier: selectedServiceIndex,
selectedService: selectedService, selectedIdNotifier: selectedServiceDBValue,
selectedServiceDBValue: selectedServiceDBValue, selectedService: selectedService!,
serviceDBValueList: serviceDBValueList, // 👈 Pass the array here
userId: userId, userId: userId,
onPolicyDataChanged: (List<Map<String, dynamic>>? policyData) { onPolicyDataChanged: (List<Map<String, dynamic>>? policyData) {
print("🟢 policyData received from child: $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 { class PolicyCriteria extends StatefulWidget {
bool isDesktop; bool isDesktop;
String selectedService; String selectedService;
String selectedServiceDBValue;
final ValueNotifier<String> selectedTabNotifier; final ValueNotifier<String> selectedTabNotifier;
final ValueNotifier<String> selectedIdNotifier;
String? userId; String? userId;
bool isClass = true; bool isClass = true;
bool isCost = true; bool isCost = true;
final List<int> serviceDBValueList;
final Function(List<Map<String, dynamic>>?) onPolicyDataChanged; final Function(List<Map<String, dynamic>>?) onPolicyDataChanged;
@ -27,18 +28,19 @@ class PolicyCriteria extends StatefulWidget {
required this.isDesktop, required this.isDesktop,
required this.selectedService, required this.selectedService,
required this.selectedTabNotifier, required this.selectedTabNotifier,
required this.selectedServiceDBValue, required this.selectedIdNotifier,
required this.userId, required this.userId,
required this.isClass, required this.isClass,
required this.isCost, required this.isCost,
required this.onPolicyDataChanged, required this.onPolicyDataChanged,
required this.serviceDBValueList,
}); });
@override @override
PolicyCriteriaState createState() => PolicyCriteriaState(); PolicyCriteriaState createState() => PolicyCriteriaState();
} }
class PolicyCriteriaState extends State<PolicyCriteria> { class PolicyCriteriaState extends State<PolicyCriteria> {
String? ServiceId = "1"; String? ServiceId;// = "1";
String? ServiceIndxId = "1"; String? ServiceIndxId = "1";
String? orgId; String? orgId;
@ -101,19 +103,32 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
fetchTrainFlightClass();
print("whole value here - ${widget.serviceDBValueList}");
print(widget.serviceDBValueList);
fieldForPolicy(); fieldForPolicy();
widget.selectedIdNotifier.addListener(() {
setState(() {
ServiceId = widget.selectedIdNotifier.value ?? "1";
print("new :) ${widget.selectedIdNotifier.value}");
print("ServiceIndxId changed: $ServiceId");
});
});
widget.selectedTabNotifier.addListener(() { widget.selectedTabNotifier.addListener(() {
print("selectedTab changed: ${widget.selectedTabNotifier.value}"); print("selectedTab changed: ${widget.selectedTabNotifier.value}");
setState(() { setState(() {
ServiceIndxId = widget.selectedTabNotifier.value ?? "1"; ServiceIndxId = widget.selectedTabNotifier.value ?? "1";
// ServiceId = widget.selectedIdNotifier.value ?? "1";
print("ServiceIndxId changed: $ServiceIndxId"); print("ServiceIndxId changed: $ServiceIndxId");
}); });
fieldForPolicy(); fieldForPolicy();
fetchTrainFlightClass(); // fetchTrainFlightClass(); // old here
}); });
} }
@ -146,6 +161,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// Step 3: Loop through all service definitions // Step 3: Loop through all service definitions
for (var service in services) { for (var service in services) {
String id = service['service_id'].toString(); String id = service['service_id'].toString();
print("164 service == $id");
// Skip if already present // Skip if already present
if (existingServiceIds!.contains(id)) continue; if (existingServiceIds!.contains(id)) continue;
@ -200,6 +216,8 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// To set the data (update) // To set the data (update)
void loadPolicyDetails(List<Map<String, dynamic>> details) { void loadPolicyDetails(List<Map<String, dynamic>> details) {
print("loadPolicyDetails");
for (var item in details) { for (var item in details) {
final serviceId = item['service_id'].toString(); 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 &&
[a1, a2, a3].where((a) => a == null).length > 0; [a1, a2, a3].where((a) => a == null).length > 0;
bool allExceptionalActionsNull = bool allExceptionalActionsNull = ae1 == null && ae2 == null && ae3 == null && ae4 == null;
ae1 == null && ae2 == null && ae3 == null && ae4 == null;
bool someExceptionalActionsMissing = bool someExceptionalActionsMissing =
[ae1, ae2, ae3, ae4].where((a) => a != null).length > 0 && [ae1, ae2, ae3, ae4].where((a) => a != null).length > 0 &&
[ae1, ae2, ae3, ae4].where((a) => a == null).length > 0; [ae1, ae2, ae3, ae4].where((a) => a == null).length > 0;
bool allAmendActionsNull = bool allAmendActionsNull = aa1 == null && aa2 == null && aa3 == null && aa4 == null;
aa1 == null && aa2 == null && aa3 == null && aa4 == null;
bool someAmendActionsMissing = bool someAmendActionsMissing =
[aa1, aa2, aa3, aa4].where((a) => a != null).length > 0 && [aa1, aa2, aa3, aa4].where((a) => a != null).length > 0 &&
[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 { Future<void> fetchTrainFlightClass() async {
print("ftech api");
try { try {
final data = await apiService.fetchMasterDropdown(); final data = await apiService.fetchMasterDropdown();
@ -460,7 +477,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
void fieldForPolicy() { void fieldForPolicy() {
print("fieldForPolicy - ${widget.selectedTabNotifier.value}"); print("fieldForPolicy - ${widget.selectedTabNotifier.value}");
print("POlicyCheck - $policyData");
// Save current input to policyData before switching // Save current input to policyData before switching
if (ServiceId != null) { if (ServiceId != null) {
print("Calling addOrUpdatePolicy"); print("Calling addOrUpdatePolicy");
@ -470,12 +487,25 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
} }
setState(() { setState(() {
// ServiceId = widget.selectedTabNotifier.value ?? "1"; // ServiceId = widget.selectedTabNotifier.value ?? "1";
ServiceId = widget.selectedServiceDBValue; final String tabIndexStr = widget.selectedTabNotifier.value;
print("ServiceId"); print(" fns - $ServiceId");
print(ServiceId); // Safely convert tab index to int
// Initialize controllers and variables if not present (Controller Creation) 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()); costController.putIfAbsent(ServiceId!, () => TextEditingController());
classAction.putIfAbsent((widget.selectedServiceDBValue), () => "1"); classAction.putIfAbsent((ServiceId!), () => "1");
// classController.putIfAbsent(ServiceId!, () => TextEditingController()); // classController.putIfAbsent(ServiceId!, () => TextEditingController());
FirstApproverAction.putIfAbsent(ServiceId!, () => "None"); FirstApproverAction.putIfAbsent(ServiceId!, () => "None");
@ -1238,10 +1268,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
children: [ children: [
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -1387,10 +1414,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
), ),
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -1540,10 +1564,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
), ),
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -1694,10 +1715,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
), ),
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -1942,10 +1960,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
children: [ children: [
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -2091,10 +2106,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
), ),
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -2244,10 +2256,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
), ),
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -2398,10 +2407,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
), ),
Container( Container(
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
horizontal: 4.0,
vertical: 4.0,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -2580,19 +2586,21 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// : (apiDataForClass?['train_class'] ?? []); // : (apiDataForClass?['train_class'] ?? []);
// } // }
if (ServiceIndxId != null) { if (ServiceId != null) {
switch (ServiceIndxId) { // ServiceId = '1';
print("sid $ServiceId");
switch (ServiceId) {
case "1": case "1":
textLabel = "Class"; textLabel = "Class";
purposeList = apiDataForClass?['flight_class'] ?? []; purposeList = apiDataForClass?['flight_class'] ?? [];
break; break;
case "2": case "5":
textLabel = "Category"; textLabel = "Category";
purposeList = apiDataForClass?['hotel_class'] ?? []; purposeList = apiDataForClass?['hotel_class'] ?? [];
break; break;
case "9": case "2":
textLabel = "Class"; textLabel = "Class";
purposeList = apiDataForClass?['train_class'] ?? []; purposeList = apiDataForClass?['train_class'] ?? [];
break; break;
@ -2606,8 +2614,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
print("CLASS-ServiceId- $ServiceId"); print("CLASS-ServiceId- $ServiceId");
print("CLASS-ServiceIndxId- $ServiceIndxId"); print("CLASS-ServiceIndxId- $ServiceIndxId");
print("CLASS-purposeList - $purposeList"); print("CLASS-purposeList - $purposeList");
print("CLASS-DB Service Id - ${widget.selectedServiceDBValue}"); print("CLASS-Action - ${classAction[ServiceId]}");
print("CLASS-Action - ${classAction[widget.selectedServiceDBValue]}");
// Sort by dropdown_key // Sort by dropdown_key
purposeList.sort((a, b) { purposeList.sort((a, b) {
@ -2626,6 +2633,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
) )
.toList(); .toList();
if (dropdownItems.isEmpty) { if (dropdownItems.isEmpty) {
dropdownItems.add( dropdownItems.add(
DropdownMenuItem<String>( DropdownMenuItem<String>(
@ -2651,14 +2659,13 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// } // }
// 1. First, when dropdownItems are ready, assign default value: // 1. First, when dropdownItems are ready, assign default value:
if ((widget.selectedServiceDBValue) != null && if ((ServiceId) != null &&
classAction[(widget.selectedServiceDBValue)] == null && classAction[ServiceId] == null &&
dropdownItems.isNotEmpty) { dropdownItems.isNotEmpty) {
// Important to wrap inside setState if async // Important to wrap inside setState if async
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() { setState(() {
classAction[(widget.selectedServiceDBValue)] = classAction[ServiceId!] = dropdownItems.first.value!;
dropdownItems.first.value!;
}); });
}); });
} }
@ -2718,18 +2725,13 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
height: 40, height: 40,
width: double.infinity, width: double.infinity,
child: child:
(widget.selectedServiceDBValue) != null && (ServiceId!) != null && (isLoading || dropdownItems.isEmpty)
(isLoading || dropdownItems.isEmpty)
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: DropdownSearch<Map<String, dynamic>>( : DropdownSearch<Map<String, dynamic>>(
key: key:
classAction[(widget.selectedServiceDBValue)] == classAction[(ServiceId!)] == null
null
? UniqueKey() ? UniqueKey()
: ValueKey( : ValueKey(classAction[(ServiceId!)]),
classAction[(widget
.selectedServiceDBValue)],
),
items: purposeList.cast<Map<String, dynamic>>(), items: purposeList.cast<Map<String, dynamic>>(),
// selectedItem: purposeList.firstWhere( // selectedItem: purposeList.firstWhere(
@ -2737,13 +2739,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
// orElse: () => {}, // orElse: () => {},
// ), // ),
selectedItem: selectedItem:
classAction[(widget.selectedServiceDBValue)] != classAction[(ServiceId!)] != null
null
? purposeList.firstWhere( ? purposeList.firstWhere(
(item) => (item) =>
item['dropdown_key'] == item['dropdown_key'] ==
classAction[(widget classAction[(ServiceId!)],
.selectedServiceDBValue)],
orElse: () => {}, orElse: () => {},
) )
: null, : null,
@ -2806,11 +2806,10 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
purposeList.isNotEmpty purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) async { ? (Map<String, dynamic>? newValue) async {
setState(() { setState(() {
classAction[(widget classAction[(ServiceId!)] =
.selectedServiceDBValue)] =
newValue?['dropdown_key']; newValue?['dropdown_key'];
print( 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? userId;
String? orgId; String? orgId;
String? roleId;
String? userIdApi; String? userIdApi;
bool isCheckingToken = false; bool isCheckingToken = false;
@ -677,6 +678,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Future<void> initializeData() async { Future<void> initializeData() async {
token = await getToken(); token = await getToken();
userId = await getUserId(); userId = await getUserId();
roleId = await getRoleId();
if (token == null || userId == null) { if (token == null || userId == null) {
print("Token or USerId missing"); print("Token or USerId missing");
@ -706,6 +708,19 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return null; 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 @override
void dispose() { void dispose() {
// Dispose all controllers to prevent memory leaks // Dispose all controllers to prevent memory leaks
@ -1313,7 +1328,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("✅ User submitted successfully!"); print("✅ User submitted successfully!");
print("📨 Response: ${response.body}"); print("📨 Response: ${response.body}");
context.go('/listUser');
if(roleId == "4"){ context.go('/listPlan'); }
else{ context.go('/listUser'); }
} else { } else {
print("❌ Submission failed. Status: ${response.statusCode}"); print("❌ Submission failed. Status: ${response.statusCode}");
print("📨 Body: ${response.body}"); print("📨 Body: ${response.body}");

View File

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

View File

@ -1,5 +1,19 @@
//api url //api url
// const String apiUrl = 'http://localhost/tstat_be'; // const String apiUrl = 'http://localhost/tstat_be';
// const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be';
const String apiUrl = // const String apiUrl = 'https://apitest.tripapprovaltool.com/tstat_be';
'http://apitest.tripapprovaltool.com/tstat_be'; // look at this
/** 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 { class ApiService {
Future<void> getOrganizationData() async { Future<void> getOrganizationData() async {
try { try {
print("getUpdatedServices"); print("ORG getUpdatedServices");
final result = await fetchOrganization(); final result = await fetchOrganization();
print("UUPdatedServices - $result"); print("UUPdatedServices - $result");