import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; class FlightListWidget extends StatefulWidget { final bool hasAction; final String? tripType; final List> flightList; final Function(bool, Map, String) onOpen; final Function(Map) onDeleteFlight; final Map? apiData; final Function(String, bool) onAddNew; final bool isViewMode; const FlightListWidget({ Key? key, required this.flightList, required this.onOpen, required this.onDeleteFlight, required this.onAddNew, required this.apiData, required this.isViewMode, required this.hasAction, this.tripType, }) : super(key: key); @override _FlightListWidgetState createState() => _FlightListWidgetState(); } class _FlightListWidgetState extends State { ApiService apiService = ApiService(); Color? layoutColor; Color? secondColor; Color? thridColor; bool orgHasService = false; // late Map countryMap; Map countryMap = {}; @override void initState() { super.initState(); loadCountryList(); // Call your method here loadInitialData(); getOrgServices(); } void loadInitialData() async { String? layoutString = await getLayoutColor(); String? secondString = await getSecondaryColor(); String? thridString = await getTernaryColor(); // String? bodyStringColor = await getBodyColor(); setState(() { layoutColor = layoutString != null ? Color(int.parse(layoutString)) : Colors.redAccent; secondColor = layoutString != null ? Color(int.parse(secondString!)) : Colors.orange; thridColor = layoutString != null ? Color(int.parse(thridString!)) : Colors.orangeAccent; // bodyColor = // bodyStringColor != null // ? Color(int.parse(bodyStringColor)) // : Colors.white; }); } void getOrgServices() async { final services = await getOrgServicesName(); print("getOrgServices storage: $services"); // just names final names = services.map((s) => s['name']).toList(); print("Names only: $names"); final hasFlight = names.contains("Flight"); setState(() { orgHasService = hasFlight; }); print("orgHasService: $orgHasService"); } Future loadCountryList() async { final result = await apiService.fetchFlightsCountryList( context, widget.tripType, ); print("ResultCountry : $result"); // Create a map: Country_Code -> "City, Airport" Map tempCountryMap = {}; for (var country in result) { // String city = country['City'] ?? ''; // String airport = country['Airport'] ?? ''; // String displayName = '${country['City']} - ${country['Airport']}'; // // String displayName = '${country['City']} | ${country['Airport']}'; final code = country['Code'] ?? ''; final city = country['City'] ?? ''; final airport = country['Airport'] ?? ''; final displayName = '$city ($code)\n$airport'; tempCountryMap[country['Code']] = displayName; } setState(() { countryMap = tempCountryMap; // Update the map }); } @override Widget build(BuildContext context) { final isDesktop = MediaQuery.of(context).size.width > 1024; ApiService apiService = ApiService(); late Map countryMap; late List countryCodes; void checkClass() { if (widget.hasAction) { if (widget.tripType?.isNotEmpty == true) { print("Teppp - $widget.tripType"); widget.onAddNew("Flight", true); } else { showDialog( context: context, builder: (context) { return AlertDialog( title: const Text('Select Trip Type'), content: const Text( 'Please select a trip type before adding a flight.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('OK'), ), ], ); }, ); } } else { print("Teppp No - $widget.tripType"); widget.onAddNew("Flight", true); } } // return Padding( // padding: const EdgeInsets.all(16.0), // child: Container( // margin: const EdgeInsets.only(top: 16.0), // child: Column( // crossAxisAlignment: CrossAxisAlignment.stretch, // children: [ // // Header with title and button // Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: [ // Text( // "Flight", // style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), // ), // widget.flightList.isNotEmpty // ? MouseRegion( // cursor: // widget.isViewMode // ? SystemMouseCursors.forbidden // : SystemMouseCursors.click, // child: GestureDetector( // onTap: // widget.isViewMode // ? null // : () { // widget.onAddNew("Flight", true); // // checkClass(); // print("New data"); // }, // child: Row( // mainAxisSize: // MainAxisSize.min, // Ensures content fits nicely // children: [ // // Text( // // "Add New", // // style: TextStyle(fontSize: 13), // // ), // // SizedBox(width: 8), // spacing between icon and text // Icon( // Icons.add_circle_sharp, // size: 30, // color: Color(0xFF114D8B), // ), // ], // ), // ), // ) // : SizedBox.shrink(), // ], // ), // const SizedBox(height: 16), // // // Scroll behavior based on device // _buildData(context, isDesktop), // ], // ), // ), // ); return Padding( padding: isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0), child: Container( margin: const EdgeInsets.only(top: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Row: Title (mobile only) + Add Button (conditional) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Title (optional on desktop or mobile) if ((!isDesktop) && widget.flightList.isNotEmpty) Text( " ", style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), // Right side: either "Add" icon or nothing if (widget.flightList.isNotEmpty && orgHasService) MouseRegion( cursor: widget.isViewMode ? SystemMouseCursors.forbidden : SystemMouseCursors.click, child: GestureDetector( onTap: widget.isViewMode ? null : () { widget.onAddNew("Flight", true); print("New data"); }, child: Icon( Icons.add_circle_sharp, size: 30, color: const Color(0xFF114D8B), ), ), ) else if (!isDesktop) SizedBox.shrink(), // 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: 18, // fontWeight: FontWeight.w500, // color: Colors.grey, // ), // ), // ), // ), ], ), isDesktop ? SizedBox(height: 16) : SizedBox(height: 5), // Actual flight data UI _buildData(context, isDesktop), ], ), ), ); } Widget _buildData(BuildContext context, bool isDesktop) { List> filteredList = widget.flightList.where((item) => item["is_active"] == "1").toList(); print("filteredList- $filteredList"); List visatypeList = widget.apiData?['flight_class'] ?? []; String getRequestForClass(String? specialRequestKey) { if (specialRequestKey == null) return "N/A"; return visatypeList .firstWhere( (element) => element["dropdown_key"].toString() == specialRequestKey, orElse: () => {"dropdown_value": "N/A"}, )["dropdown_value"] .toString(); } // String formatDate(String dateString) { // try { // DateTime date = DateTime.parse(dateString); // return DateFormat('d MMM yy').format(date); // Example: 4 Apr 25 // } catch (e) { // return "Invalid Date"; // } // } // // String formatTime(String timeString) { // try { // final parts = timeString.split(':'); // final now = DateTime.now(); // final dateTime = DateTime( // now.year, // now.month, // now.day, // int.parse(parts[0]), // int.parse(parts[1]), // ); // return DateFormat.jm().format(dateTime); // e.g., 12:16 PM or 12 AM // } catch (e) { // return "Invalid Time"; // } // } String formatDate(String dateString) { try { DateTime date = DateFormat("dd-MM-yyyy").parse(dateString); return DateFormat('dd MMM yy').format(date); // Example: 23 May 25 } catch (e) { return "Invalid Date"; } } String formatTime(String timeString) { try { final parts = timeString.split(':'); int hour = int.parse(parts[0]); int minute = int.parse(parts[1]); final now = DateTime.now(); DateTime dateTime; if (hour == 24 && minute == 0) { // 24:00 is treated as 00:00 on the next day dateTime = DateTime( now.year, now.month, now.day, ).add(const Duration(days: 1)); } else { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { throw FormatException("Invalid hour or minute"); } dateTime = DateTime(now.year, now.month, now.day, hour, minute); } return DateFormat('HH:mm').format(dateTime); // 24-hour format } catch (e) { return "Invalid Time"; } } return ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: filteredList.length, itemBuilder: (context, index) { final item = filteredList[index]; String? tripTypeName = ''; switch (item["trip_type"]?.toString()) { case "Roundtrip": tripTypeName = "Round Trip"; break; case "Multitrip": tripTypeName = "Multi-Trip"; break; case "Oneway": tripTypeName = "One-Way"; break; default: tripTypeName = item["trip_type"]?.toString(); break; } return Container( margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), // color: isDesktop ? Colors.white : Color(0xFFFFF0F5), color: isDesktop ? Colors.white : thridColor, // color: Colors.orange.shade50, // color: Colors.white, boxShadow: isDesktop ? [ BoxShadow( color: Colors.black12, blurRadius: 2, offset: Offset(0, 2), // down ), // Top shadow BoxShadow( color: Colors.black12, blurRadius: 0.5, offset: Offset(0, -1), // up ), ] : [], border: Border( top: BorderSide( color: Colors.white70, // Change color to match your theme width: 2, ), ), ), child: Padding( padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 2), child: Row( children: [ Text( tripTypeName ?? "N/A", style: GoogleFonts.poppins( fontSize: 14, fontWeight: isDesktop ? FontWeight.w800 : FontWeight.w600, color: !isDesktop ? Colors.black : Color(0xFF575A74), // Color(0xFF114D8B) ), ), Spacer(), if (orgHasService) ...[ GestureDetector( onTap: () => widget.onOpen(true, item, "Flight"), child: Tooltip( message: 'Edit Flight Details', child: Image.asset( 'assets/images/IconsImg/edit.png', width: 20, height: 15, color: isDesktop ? Color(0xFF114D8B) : Colors.black87, ), ), ), SizedBox(width: 10), GestureDetector( onTap: () => widget.onDeleteFlight(item), child: Tooltip( message: 'Delete Flight Details', child: Image.asset( 'assets/images/IconsImg/delete.png', width: 20, height: 15, color: Colors.red, ), ), ), ], ], ), ), // Divider(color: Colors.blueGrey.shade50), SizedBox(height: 4), if (isDesktop) Row( children: [ Expanded( flex: 2, child: Text( "Class", style: GoogleFonts.poppins(fontSize: 11), ), ), Expanded( flex: 5, child: Text( "Sector", style: GoogleFonts.poppins(fontSize: 11), ), ), Expanded( flex: 2, child: Text( "Date", style: GoogleFonts.poppins(fontSize: 11), ), ), Expanded( flex: 2, child: Text( "Time", style: GoogleFonts.poppins(fontSize: 11), ), ), ], ), SizedBox(height: 4), // Trip Rows if (isDesktop) if (item["trips"] != null && item["trips"].isNotEmpty) ...item["trips"].map((trip) { print("werewrewrTrip - $trip"); String fromPlaceCountry = countryMap[trip["from_place"]?.toString()] ?? "Unknown Country"; final parts = fromPlaceCountry.split('\n'); final cityAndCode = parts[0]; final fromairport = parts.length > 1 ? parts[1] : ''; // Extract city and code from "City (CODE)" final cityMatch = RegExp( r'^(.*)\s+\(([^)]+)\)$', ).firstMatch(cityAndCode); final fromcity = cityMatch?.group(1) ?? ''; final fromcode = cityMatch?.group(2) ?? ''; String toPlaceCountry = countryMap[trip["to_place"]?.toString()] ?? "Unknown Country"; final toparts = toPlaceCountry.split('\n'); final tocityAndCode = toparts[0]; final toairport = toparts.length > 1 ? toparts[1] : ''; // Extract city and code from "City (CODE)" final tocityMatch = RegExp( r'^(.*)\s+\(([^)]+)\)$', ).firstMatch(tocityAndCode); final tocity = tocityMatch?.group(1) ?? ''; final tocode = tocityMatch?.group(2) ?? ''; return Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( children: [ Expanded( flex: 2, child: Text( getRequestForClass(trip["class"].toString()) ?? "N/A", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w700, ), ), ), Expanded( flex: 4, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "$fromcity ($fromcode)", // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w700, ), ), Text( "$fromairport", // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", style: GoogleFonts.poppins( fontSize: 10, fontWeight: FontWeight.w400, ), ), ], ), ), Expanded( flex: 1, child: Padding( padding: const EdgeInsets.only(left: 10), child: Image.asset( 'assets/images/IconsImg/Frame.png', width: 20, height: 20, ), ), ), Expanded( flex: 1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "$tocity ($tocode)", // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w700, ), ), Text( "$toairport", // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", style: GoogleFonts.poppins( fontSize: 10, fontWeight: FontWeight.w400, ), ), ], ), ), ], ), ), Spacer(), Expanded( flex: 2, child: Text( formatDate(trip["date"] ?? ""), style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w700, ), ), ), Expanded( flex: 2, child: Text( formatTime(trip["time"] ?? ""), style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w700, ), ), ), ], ), ); }).toList(), if (!isDesktop && item["trips"] != null && item["trips"].isNotEmpty) ...item["trips"].map((trip) { String fromPlaceCountry = countryMap[trip["from_place"]?.toString()] ?? "Unknown Country"; final parts = fromPlaceCountry.split('\n'); final cityAndCode = parts[0]; final fromairport = parts.length > 1 ? parts[1] : ''; // Extract city and code from "City (CODE)" final cityMatch = RegExp( r'^(.*)\s+\(([^)]+)\)$', ).firstMatch(cityAndCode); final fromcity = cityMatch?.group(1) ?? ''; final fromcode = cityMatch?.group(2) ?? ''; String toPlaceCountry = countryMap[trip["to_place"]?.toString()] ?? "Unknown Country"; final toparts = toPlaceCountry.split('\n'); final tocityAndCode = toparts[0]; final toairport = toparts.length > 1 ? toparts[1] : ''; // Extract city and code from "City (CODE)" final tocityMatch = RegExp( r'^(.*)\s+\(([^)]+)\)$', ).firstMatch(tocityAndCode); final tocity = tocityMatch?.group(1) ?? ''; final tocode = tocityMatch?.group(2) ?? ''; return Padding( padding: const EdgeInsets.symmetric(vertical: 6.0), child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(6), color: Colors.grey.shade50, ), padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildKeyValueRow( "Class", getRequestForClass(trip["class"].toString()) ?? "N/A", ), _buildKeyValueRow( "From", "$fromcity ($fromcode), $fromairport ", ), _buildKeyValueRow( "To", "$tocity ($tocode), $toairport", ), _buildKeyValueRow( "Date", formatDate(trip["date"] ?? ""), ), _buildKeyValueRow( "Time", formatTime(trip["time"] ?? ""), ), ], ), ), ); // return Padding( // padding: const EdgeInsets.symmetric(vertical: 6.0), // child: Container( // // decoration: BoxDecoration( // // border: Border.all(color: Colors.grey.shade300), // // borderRadius: BorderRadius.circular(6), // // color: Colors.grey.shade50, // // ), // // padding: const EdgeInsets.all(12), // child: Row( // children: [ // /// LEFT SIDE: Class and Airport Info // Expanded( // flex: 2, // child: Row( // children: [ // Text( // '${getRequestForClass(trip["class"].toString()) ?? "N/A"} (', // style: const TextStyle( // fontWeight: FontWeight.bold, // fontSize: 14, // color: Colors.black87, // ), // ), // Text( // // fromairport, // fromcode, // style: const TextStyle( // fontWeight: FontWeight.bold, // fontSize: 14, // color: Colors.black87, // ), // ), // const Padding( // padding: EdgeInsets.symmetric( // horizontal: 6, // ), // child: Image( // image: AssetImage( // 'assets/images/IconsImg/Frame.png', // ), // width: 18, // height: 18, // ), // ), // Text( // '$tocode)', // // '$toairport)', // style: const TextStyle( // fontWeight: FontWeight.bold, // fontSize: 14, // color: Colors.black87, // ), // ), // ], // ), // ), // // /// RIGHT SIDE: Date and Time // Expanded( // flex: 1, // child: Text( // '${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}', // textAlign: TextAlign.right, // style: const TextStyle( // fontSize: 13, // color: Colors.black87, // ), // ), // ), // ], // ), // ), // ); // return Padding( // padding: const EdgeInsets.symmetric(vertical: 6.0), // child: Container( // child: Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Wrap( // crossAxisAlignment: WrapCrossAlignment.center, // spacing: 4, // runSpacing: 4, // children: [ // Text( // '${getRequestForClass(trip["class"].toString()) ?? "N/A"} (', // style: const TextStyle( // fontWeight: FontWeight.bold, // fontSize: 14, // color: Colors.black87, // ), // ), // Text( // fromcode, // style: const TextStyle( // fontWeight: FontWeight.bold, // fontSize: 14, // color: Colors.black87, // ), // ), // const Padding( // padding: EdgeInsets.symmetric(horizontal: 4), // child: Image( // image: AssetImage('assets/images/IconsImg/Frame.png'), // width: 18, // height: 18, // ), // ), // Text( // '$tocode)', // style: const TextStyle( // fontWeight: FontWeight.bold, // fontSize: 14, // color: Colors.black87, // ), // ), // ], // ), // const SizedBox(height: 6), // Align( // alignment: Alignment.centerRight, // child: Text( // '${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}', // textAlign: TextAlign.right, // style: const TextStyle( // fontSize: 13, // color: Colors.black87, // ), // ), // ), // ], // ), // ), // ); }).toList(), ], ), ), ); }, ); } Widget _buildKeyValueRow(String key, String value) { return Padding( padding: const EdgeInsets.only(bottom: 4.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 70, // adjust width as needed child: Text( "$key", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), Expanded( child: Text(value, style: GoogleFonts.poppins(fontSize: 12)), ), ], ), ); } }