ts-tat/lib/Screens/itnerary/flights.dart
2025-10-27 17:35:57 +05:30

3907 lines
158 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
import '../../utils/auth_utils.dart';
import '../../widgets/custom_confirmation_dialog.dart';
import '../../widgets/custom_radio_button.dart';
import '../../widgets/custom_text_field.dart';
import '../../widgets/custom_text_itnerary_sub.dart';
class FlightScreen extends StatefulWidget {
final bool hasAction;
final String? tripType;
final List<Map<String, dynamic>> flightData;
final Map<String, dynamic>? apiData;
final Map<String, dynamic>? apiDataForClass;
final String? loginUser;
final Function(String, bool) onClose;
final Function(Map<String, dynamic>) onSaveFlight;
final Map<String, dynamic>? selectedItem;
final ValueNotifier<String?> tripTypeNotifier;
FlightScreen({
Key? key,
required this.apiData,
required this.loginUser,
required this.onClose,
required this.onSaveFlight,
required this.selectedItem,
required this.flightData,
required this.hasAction,
this.tripType,
required this.tripTypeNotifier,
this.apiDataForClass,
}) : super(key: key);
@override
FlightScreenState createState() => FlightScreenState();
}
class FlightScreenState extends State<FlightScreen> {
ApiService apiService = ApiService();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String plantripType = "";
bool isCountryLoading = true;
late Map<String, String> countryMap;
late Map<String, String> countryCodeMap;
late List<String> countryCodes;
late ValueNotifier<String?> flightFirstTripDateNotifier;
late ValueNotifier<String?> flightLastTripDateNotifier;
String? selectedCountry;
List<Map<String, dynamic>> countryList = [];
Map<String, String?> selectedValues = {};
int rowCount = 1;
String? selectedTripType;
Map<int, String?> selectedClasses = {}; // Store class selection for each trip
Map<int, String?> exceptionalClass =
{}; // Store class selection for each trip
Map<int, String?> selectedFrom = {}; // Store class selection for each trip
Map<int, String?> selectedTo = {}; // Store class selection for each trip
String? selectedvisa_available;
int multiTripRowCount = 1;
// Color? layoutColor;
Color layoutColor = Colors.grey;
List<String> dataHeader = [
"_tripType",
"_class",
"_from",
"_to",
"_date",
"_visa",
"_time",
"_comments",
];
Map<String, FocusNode> focusNodes = {};
Map<String, bool> focusStates = {};
Map<String, TextEditingController> textControllers = {};
Map<String, String> fieldErrors = {}; // Holds error messages
List<List<Widget>> rowBuilders = []; // Holds row widgets
List<TextEditingController> controllers = []; // Dynamic controllers
bool _hasInitialTripTypeLoaded = false;
Map<String, String> errorMessages = {};
// forex_pre_paid_card_number
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
loadInitialData();
});
print("TripType - ${widget.tripType}");
setState(() {
plantripType = widget.tripType!;
});
// final newTripType = widget.tripTypeNotifier.value;
// print("TripType1 - $newTripType");
// // Listen immediately
// widget.tripTypeNotifier.addListener(() {
// final newTripType = widget.tripTypeNotifier.value;
//
// if (newTripType != null && newTripType.isNotEmpty) {
// if (_hasInitialTripTypeLoaded) {
// print("🚀 FlightScreen reacting to new trip type: $newTripType");
// loadCountryList(newTripType);
// } else {
// print("🟡 Skipping initial tripTypeNotifier value: $newTripType");
// _hasInitialTripTypeLoaded = true;
// }
// }
// });
// _initializeRows();
// List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
// selectedTripType ??= purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
// Get trip type from widget.selectedItem
selectedTripType = widget.selectedItem?["trip_type"] as String?;
// If null, set it to the first available value from purposeList
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
if (selectedTripType == null && purposeList.isNotEmpty) {
selectedTripType = purposeList.first['dropdown_value'] as String?;
}
_initializeFields();
getRowCount();
print("Focus Nodes Keys: ${focusNodes.keys.toList()}");
print("Focus States Keys: ${focusStates.keys.toList()}");
print("Text Controllers Keys: ${textControllers.keys.toList()}");
for (var key in focusNodes.keys) {
_addFocusListener(focusNodes[key]!, (focus) {
setState(() {
focusStates[key.replaceFirst("FocusNode", "Focused")] = focus;
});
});
}
handleUpdateField();
int rowCount = 1; // Default row count for One-way
if (selectedTripType == "Roundtrip") {
rowCount = 2; // Fixed for Roundtrip
} else if (selectedTripType == "Multitrip") {
rowCount = multiTripRowCount; // Dynamic row count for Multitrip
}
// Loop through each row and add listeners to clear errors
for (int i = 1; i <= rowCount; i++) {
textControllers["_from${i}Controller"]?.addListener(
() => _clearError("from_place_$i"),
);
textControllers["_to${i}Controller"]?.addListener(
() => _clearError("to_place_$i"),
);
textControllers["_date${i}Controller"]?.addListener(
() => _clearError("date_$i"),
);
textControllers["_time${i}Controller"]?.addListener(
() => _clearError("time_$i"),
);
}
// loadCountryList();
flightFirstTripDateNotifier = ValueNotifier<String?>(null);
flightLastTripDateNotifier = ValueNotifier<String?>(null);
WidgetsBinding.instance.addPostFrameCallback((_) {
final result = getFlightTripDateRange(widget.flightData);
flightFirstTripDateNotifier.value = result['firstTripDate'];
flightLastTripDateNotifier.value = result['lastTripDate'];
final tripTypeValue = widget.tripTypeNotifier.value;
if (tripTypeValue != null && tripTypeValue.isNotEmpty) {
print("🚀 Initial loadCountryList for tripType: $tripTypeValue");
loadCountryList(context, tripTypeValue);
} else {
print("⚠️ tripType is null or empty, skipping loadCountryList");
}
});
}
Map<String, String?> getFlightTripDateRange(
List<Map<String, dynamic>> flightData,
) {
final allTrips =
flightData
.expand((flight) => flight['trips'] ?? [])
.whereType<Map<String, dynamic>>()
.toList();
if (allTrips.isEmpty) {
return {'firstTripDate': null, 'lastTripDate': null};
}
allTrips.sort((a, b) {
final aDate = DateTime.tryParse(a['date'] ?? '') ?? DateTime(1900);
final bDate = DateTime.tryParse(b['date'] ?? '') ?? DateTime(1900);
return aDate.compareTo(bDate);
});
final firstTrip = allTrips.first;
final lastTrip = allTrips.last;
return {
'firstTripDate': firstTrip['date'],
'lastTripDate': lastTrip['date'],
};
}
//
// Future<void> loadCountryList() async {
// setState(() {
// isCountryLoading = true;
// });
//
// final result = await apiService.fetchFlightsCountryList();
//
// if (result is List) {
// countryList =
// result.map((item) => Map<String, dynamic>.from(item)).toList();
// countryMap = {
// for (var item in countryList)
// if (item['country_code'] != null && item['country_name'] != null)
// item['country_code'] as String: item['country_name'] as String
// };
// countryCodes = countryMap.keys.toList();
// } else {
// countryList = [];
// countryMap = {};
// countryCodes = [];
// }
//
// setState(() {
// isCountryLoading = false;
// });
// }
Future<void> loadCountryList(BuildContext context, newTripType) async {
print("🔄 loadCountryList called with tripType: ${newTripType}");
setState(() {
isCountryLoading = true;
});
final result = await apiService.fetchFlightsCountryList(
context,
newTripType,
);
print("ResultCountry : $result");
// Create a map: Country_Code -> "City, Airport"
Map<String, String> tempCountryMap = {};
Map<String, String> tempCountryCode = {};
for (var country in result) {
// String city = country['City'] ?? '';
// String airport = country['Airport'] ?? '';
// String displayName = '${country['City']} - ${country['Airport']}';
final code = country['Code'] ?? '';
final city = country['City'] ?? '';
final airport = country['Airport'] ?? '';
final countyCode = country['Country_Code'] ?? '';
final displayName = '$city ($code)\n$airport';
tempCountryMap[country['Code']] = displayName;
tempCountryCode[country['Code']] = countyCode;
}
setState(() {
countryMap = tempCountryMap; // Update the map
countryCodeMap = tempCountryCode;
isCountryLoading = false;
});
}
int getRowCount() {
if (selectedTripType == "RoundTrip") {
return 2;
} else if (selectedTripType == "Multitrip") {
return multiTripRowCount;
}
return 1; // Default for Oneway
}
void loadInitialData() async {
String? layoutString = await getLayoutColor();
// setState(() {
// layoutColor =
// layoutString != null
// ? Color(int.parse(layoutString))
// : Colors.redAccent;
// });
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
});
}
void _initializeFields() {
print("_initializeFields-----------------");
// Dispose and clear previous controllers and focus nodes
for (var key in List.from(textControllers.keys)) {
textControllers[key]?.dispose();
}
textControllers.clear();
for (var key in List.from(focusNodes.keys)) {
focusNodes[key]?.dispose();
}
focusNodes.clear();
textControllers.clear();
focusNodes.clear();
focusStates.clear();
print("Focus Nodes KeysII: ${focusNodes.keys.toList()}");
print("Focus States KeysII: ${focusStates.keys.toList()}");
print("Text Controllers KeysII: ${textControllers.keys.toList()}");
// Determine the row count based on selectedTripType
int rowCount =
selectedTripType == "Roundtrip"
? 2
: selectedTripType == "Multitrip"
? multiTripRowCount
: 1;
// Initialize fields dynamically
for (var field in dataHeader) {
for (int i = 1; i <= rowCount; i++) {
textControllers["${field}${i}Controller"] = TextEditingController();
focusNodes["${field}${i}FocusNode"] = FocusNode();
focusStates["${field}${i}Focused"] = false;
}
}
// Add focus listeners after reinitialization
for (var key in focusNodes.keys) {
_addFocusListener(focusNodes[key]!, (focus) {
setState(() {
focusStates[key.replaceFirst("FocusNode", "Focused")] = focus;
});
});
}
setState(() {}); // Ensure UI updates
}
void addMultiTripRow() {
setState(() {
multiTripRowCount++; // Increment row count
_initializeFields(); // Reinitialize fields with updated count
});
}
void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() {
setState(() {
updateState(node.hasFocus);
});
});
}
void _clearError(String field) {
if (mounted && errorMessages.containsKey(field)) {
setState(() {
errorMessages.remove(field);
});
}
}
@override
void dispose() {
// _tripTypeFocusNode.dispose();
// Dispose all dynamically created FocusNodes
for (var node in focusNodes.values) {
node.dispose();
}
// Dispose all dynamically created TextEditingControllers
for (var controller in textControllers.values) {
controller.dispose();
}
super.dispose();
}
Map<String, dynamic> get flightsData {
List<Map<String, dynamic>> trips = [];
int rowCount = 1; // Default for One-way
if (selectedTripType == "Roundtrip") {
rowCount = 2; // Fixed count for Roundtrip
} else if (selectedTripType == "Multitrip") {
rowCount = multiTripRowCount; // Use dynamic count for Multitrip
}
for (int i = 1; i <= rowCount; i++) {
final trip = {
"class": selectedClasses[i],
"is_this_exceptional": exceptionalClass[i],
// "from_place": countryMap[selectedFrom[i]],
"from_place": selectedFrom[i],
"to_place": selectedTo[i],
"from_country_code": countryCodeMap[selectedFrom[i]],
"to_country_code": countryCodeMap[selectedTo[i]],
// "from_place": textControllers["_from${i}Controller"]?.text ?? "",
// "to_place": textControllers["_to${i}Controller"]?.text ?? "",
"date": textControllers["_date${i}Controller"]?.text ?? "",
"time": textControllers["_time${i}Controller"]?.text ?? "",
"created_by": widget.loginUser,
"updated_by": widget.loginUser,
};
// Check if editing and flight_trip_id exists for this trip
// 🛠 Fix index offset (i - 1)
if (widget.selectedItem != null &&
widget.selectedItem?["trips"] != null &&
widget.selectedItem!["trips"] is List &&
(i - 1) < widget.selectedItem!["trips"].length) {
final existingTrip = widget.selectedItem!["trips"][i - 1];
if (existingTrip["flight_trip_id"] != null) {
trip["flight_trip_id"] = existingTrip["flight_trip_id"];
}
}
trips.add(trip);
// trips.add({
// "class": selectedClasses[i],
// "from_place": textControllers["_from${i}Controller"]?.text ?? "",
// "to_place": textControllers["_to${i}Controller"]?.text ?? "",
// "date": textControllers["_date${i}Controller"]?.text ?? "",
// "time": textControllers["_time${i}Controller"]?.text ?? "",
// "created_by": widget.loginUser,
// "updated_by": widget.loginUser,
// });
}
Map<String, dynamic> data = {
"trip_type": selectedTripType,
"comments": textControllers["_comments1Controller"]?.text ?? "",
"visa_available": selectedvisa_available ?? "",
"created_by": widget.loginUser,
"updated_by": widget.loginUser,
"trips": trips,
};
if (widget.selectedItem != null) {
if (widget.selectedItem?["indx"] != null &&
widget.selectedItem?["indx"] != 0) {
data["indx"] = widget.selectedItem!["indx"];
} else if (widget.selectedItem?["flight_id"] != null &&
widget.selectedItem?["flight_id"] != 0) {
data["flight_id"] = widget.selectedItem!["flight_id"];
}
}
return data;
}
TextEditingController initController(String key) {
return TextEditingController(text: widget.selectedItem?[key] ?? "");
}
void handleUpdateField() {
if (widget.selectedItem != null) {
textControllers["_comments1Controller"] = initController("comments");
// selectedTripType = widget.selectedItem!["trip_type"] as String?;
// selectedvisa_available = widget.selectedItem!["visa_available"].toString();
if (widget.selectedItem!["trip_type"] != null) {
selectedTripType = widget.selectedItem!["trip_type"].toString();
}
if (widget.selectedItem!["visa_available"] != null) {
selectedvisa_available =
widget.selectedItem!["visa_available"].toString();
}
// Extract trips from selectedItem
List<dynamic> selectedTrips = widget.selectedItem!["trips"] ?? [];
// Ensure the selectedClasses map and textControllers are cleared before populating
// selectedClasses.clear();
// textControllers.clear();
// Set row count dynamically for Multitrip
if (selectedTripType == "Multitrip") {
multiTripRowCount = selectedTrips.length;
}
// Loop through selected trips and populate text controllers
for (int i = 0; i < selectedTrips.length; i++) {
var trip = selectedTrips[i] as Map<String, dynamic>;
int index = i + 1; // Use 1-based indexing to match the form
selectedClasses[index] = trip["class"].toString();
exceptionalClass[index] = trip["is_this_exceptional"].toString();
selectedFrom[index] = trip["from_place"].toString();
selectedTo[index] = trip["to_place"].toString();
// textControllers["_from${index}Controller"] =
// TextEditingController(text: trip["from_place"]);
// textControllers["_to${index}Controller"] =
// TextEditingController(text: trip["to_place"]);
textControllers["_date${index}Controller"] = TextEditingController(
text: trip["date"],
);
textControllers["_time${index}Controller"] = TextEditingController(
text: trip["time"],
);
// Check if editing and flight_trip_id exists for this trip
if (widget.selectedItem != null &&
widget.selectedItem?["trips"] != null &&
widget.selectedItem!["trips"] is List &&
i < widget.selectedItem!["trips"].length) {
final existingTrip = widget.selectedItem!["trips"][i];
if (existingTrip["flight_trip_id"] != null) {
trip["flight_trip_id"] = existingTrip["flight_trip_id"];
}
}
}
print("Selected ITEM - ${widget.selectedItem}");
print("Total Trips Loaded: ${selectedTrips.length}");
print("Controllers Set: ${textControllers.keys}");
}
}
void handleSave() {
print("Controllers Key-Value Pairs:");
if (!validateFields()) {
print("Validation failed. Please fill all required fields.");
return;
}
widget.onSaveFlight(flightsData); // Send object to parent
// widget.onClose(false);
widget.onClose("Flight", false);
print("FlightData - $flightsData");
}
void validateTimeDifference(int index) {
if (index <= 1) return; // Skip validation for the first row
String? prevDateStr = textControllers["_date${index - 1}Controller"]?.text;
String? prevTimeStr = textControllers["_time${index - 1}Controller"]?.text;
String? currDateStr = textControllers["_date${index}Controller"]?.text;
String? currTimeStr = textControllers["_time${index}Controller"]?.text;
print("prevDateTime - $prevTimeStr");
print("currDateTime - $currTimeStr");
if (prevDateStr != null &&
prevDateStr.isNotEmpty &&
prevTimeStr != null &&
prevTimeStr.isNotEmpty &&
currDateStr != null &&
currDateStr.isNotEmpty &&
currTimeStr != null &&
currTimeStr.isNotEmpty) {
try {
final format = DateFormat("dd-MM-yyyy HH:mm");
// final prevDateTime = DateTime.parse("$prevDateStr $prevTimeStr");
// final currDateTime = DateTime.parse("$currDateStr $currTimeStr");
final prevDateTime = format.parse("$prevDateStr $prevTimeStr");
final currDateTime = format.parse("$currDateStr $currTimeStr");
if (!currDateTime.isAfter(prevDateTime)) {
errorMessages["time_$index"] = "30 mins gap required";
} else if (currDateTime.difference(prevDateTime).inMinutes < 30) {
errorMessages["time_$index"] = "30 mins gap required";
} else {
errorMessages.remove("time_$index");
}
} catch (e) {
print(" Invalid time format");
errorMessages["time_$index"] = "Invalid time format";
}
}
}
bool validateFields() {
errorMessages.clear(); // Reset errors
rowCount = 1; // Default row count for One-way
if (selectedTripType == "Roundtrip") {
rowCount = 2; // Fixed for Roundtrip
} else if (selectedTripType == "Multitrip") {
rowCount = multiTripRowCount; // Dynamic row count for Multitrip
}
// Loop through each trip row and validate required fields
for (int i = 1; i <= rowCount; i++) {
// if (textControllers["_from${i}Controller"]?.text.trim().isEmpty ?? true) {
// errorMessages["from_place_$i"] = "Required";
// }
if (selectedFrom[i] == null) {
errorMessages["from_place_$i"] = "Required";
}
// if (selectedTo[i] == null) {
// errorMessages["to_place_$i"] = "Required";
// }else if (
// selectedFrom[i] == selectedTo[i]) {
// errorMessages["to_place_$i"] = "Change Destination";
// }
if (selectedTo[i] == null) {
errorMessages["to_place_$i"] = "Required";
print("Error: to_place_$i -> Required (selectedTo[$i] is null)");
} else if (selectedFrom[i] == selectedTo[i]) {
if (selectedTripType == "Roundtrip") {
errorMessages["to_place_1"] = "Change Destination";
} else {
errorMessages["to_place_$i"] = "Change Destination";
}
print(
"Error: to_place_$i -> Change Destination (selectedFrom[$i] == selectedTo[$i])",
);
}
// if (textControllers["_to${i}Controller"]?.text.trim().isEmpty ?? true) {
// errorMessages["to_place_$i"] = "Required";
// }
// if (textControllers["_date${i}Controller"]?.text.trim().isEmpty ?? true) {
// errorMessages["date_$i"] = "Required";
// }
if (textControllers["_date${i}Controller"]?.text.trim().isEmpty ?? true) {
errorMessages["date_$i"] = "Required";
}
if (selectedClasses[i] == null) {
errorMessages["class_$i"] = "Required";
}
if (textControllers["_time${i}Controller"]?.text.trim().isEmpty ?? true) {
errorMessages["time_$i"] = "Required";
}
}
//selectedFrom For every trips should n't same
Set<String?> seenFrom = {};
Set<String?> seenTo = {};
if (selectedTripType == "Roundtrip") {
for (int i = 1; i <= rowCount; i++) {
final fromValue = selectedFrom[i];
final toValue = selectedTo[i];
if (fromValue != null) {
if (seenFrom.contains(fromValue)) {
errorMessages["from_place_$i"] = "Duplicate Departure ";
print("Error: from_place_$i duplicates a previous departure");
} else {
seenFrom.add(fromValue);
// errorMessages.remove("from_place_$i");
}
}
if (toValue != null) {
if (seenTo.contains(toValue)) {
errorMessages["to_place_$i"] = "Duplicate Destination ";
print("Error: to_place_$i duplicates a previous departure");
} else {
// errorMessages.remove("to_place_$i");
seenTo.add(toValue);
}
}
}
}
// Step 3: Sequential Date Comparison
DateFormat format = DateFormat("dd-MM-yyyy"); // Assumes "12 Jun" format
DateTime now = DateTime.now();
List<DateTime> parsedDates = [];
for (int i = 1; i <= rowCount; i++) {
String? dateStr = textControllers["_date${i}Controller"]?.text.trim();
String? timeStr = textControllers["_time${i}Controller"]?.text.trim();
print("VAlidationDATE - $dateStr ");
if (dateStr != null && dateStr.isNotEmpty) {
try {
DateTime date = format.parseStrict(dateStr);
date = DateTime(
date.year,
date.month,
date.day,
); // Assume current year
parsedDates.add(date);
} catch (e) {
errorMessages["date_$i"] = "Invalid format";
}
}
}
for (int i = 1; i < parsedDates.length; i++) {
if (parsedDates[i].isAtSameMomentAs(parsedDates[i - 1])) {
//Here check time[i] and time[i-1] if same error 30 mins gap reeuired
print("Ckecking Same DAte");
// Same date - check time gap
// Combine parsedDates and times into DateTime objects
String prevDateStr =
textControllers["_date${i}Controller"]!.text.trim();
String prevTimeStr =
textControllers["_time${i}Controller"]!.text.trim();
String currDateStr =
textControllers["_date${i + 1}Controller"]!.text.trim();
String currTimeStr =
textControllers["_time${i + 1}Controller"]!.text.trim();
final dtFormat = DateFormat("dd-MM-yyyy HH:mm");
final prevDT = dtFormat.parse("$prevDateStr $prevTimeStr");
final currDT = dtFormat.parse("$currDateStr $currTimeStr");
int diffMins = currDT.difference(prevDT).inMinutes;
print("Time difference between row ${i} and ${i + 1}: $diffMins mins");
// If same day (diff >= 0 & < 1440 minutes), enforce 30min minimum gap
if (diffMins < 0) {
errorMessages["time_${i + 1}"] = "Must be after previous";
} else if (diffMins < 30) {
errorMessages["time_${i + 1}"] = "30 mins gap required";
} else {
errorMessages.remove("time_${i + 1}");
}
print("Ckecking Same DAte...1");
} else if (!parsedDates[i].isAfter(parsedDates[i - 1])) {
errorMessages["date_${i + 1}"] = "Must be after date_${i}";
print("Error: date_${i + 1} is not after date_${i}");
} else {
errorMessages.remove("date_${i + 1}");
}
}
setState(() {}); // Update UI to show error messages
return errorMessages
.isEmpty; // Returns true if all required fields are filled
}
void removeTrip(int index) {
if (selectedTripType == "Multitrip" && multiTripRowCount > 1) {
print("Delete Index - $index");
setState(() {
multiTripRowCount--; // Reduce trip count
// Remove corresponding text controllers
textControllers.remove("_from${index}Controller");
textControllers.remove("_to${index}Controller");
textControllers.remove("_date${index}Controller");
textControllers.remove("_time${index}Controller");
// Step 2: Shift remaining textControllers keys
Map<String, TextEditingController> updatedTextControllers = {};
int newIndex = 1;
for (int i = 1; i <= multiTripRowCount + 1; i++) {
if (i == index) continue; // Skip the deleted one
// updatedTextControllers["_from${newIndex}Controller"] =
// textControllers["_from${i}Controller"]!;
updatedTextControllers["_to${newIndex}Controller"] =
textControllers["_to${i}Controller"]!;
updatedTextControllers["_date${newIndex}Controller"] =
textControllers["_date${i}Controller"]!;
updatedTextControllers["_time${newIndex}Controller"] =
textControllers["_time${i}Controller"]!;
newIndex++;
}
textControllers = updatedTextControllers;
// Shift the selectedClasses map BEFORE removing the index
Map<int, String?> updatedClasses = {};
newIndex = 1;
for (int i = 1; i <= selectedClasses.length; i++) {
if (i == index) continue; // Skip the one being deleted
updatedClasses[newIndex] = selectedClasses[i];
newIndex++;
}
selectedClasses = updatedClasses; // Update the map
Map<int, String?> updatedExptionalClasses = {};
newIndex = 1;
for (int i = 1; i <= exceptionalClass.length; i++) {
if (i == index) continue; // Skip the one being deleted
updatedExptionalClasses[newIndex] = exceptionalClass[i];
newIndex++;
}
exceptionalClass = updatedExptionalClasses;
// Shift the selectedFrom map BEFORE removing the index
Map<int, String?> updatedFrom = {};
newIndex = 1;
for (int i = 1; i <= selectedFrom.length; i++) {
if (i == index) continue; // Skip the one being deleted
updatedFrom[newIndex] = selectedFrom[i];
newIndex++;
}
selectedFrom = updatedFrom;
// Shift the selectedTo map BEFORE removing the index
Map<int, String?> updatedTo = {};
newIndex = 1;
for (int i = 1; i <= selectedTo.length; i++) {
if (i == index) continue; // Skip the one being deleted
updatedTo[newIndex] = selectedTo[i];
newIndex++;
}
selectedTo = updatedTo;
print("FlightData - $flightsData");
print("Updated Trips: $multiTripRowCount");
print("Updated Classes: $selectedClasses");
});
}
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile;
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Container(
// color: Color(0xFFF4F4FB),
// color: Color(0xFFF9F9F9), // Slightly lighter than white
child: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)),
),
),
],
),
),
),
);
},
);
}
List<Widget> _buildAccomadtionForm(bool isDesktop) {
List<Widget> buildResponsiveRow(List<Widget> children) {
return [
isDesktop ? Row(children: children) : Column(children: children),
SizedBox(height: 10),
];
}
List<List<Widget>> rowBuilders = [
// _builClassType(isDesktop, 1),
_buildSecondRow(isDesktop, 1),
];
List<List<Widget>> rowRoundBuilders = [
// _builClassType(isDesktop, 1),
_buildSecondRow(isDesktop, 1),
// _builClassType(isDesktop, 2),
_buildSecondRow(isDesktop, 2),
];
print("Trip Type Selected: $selectedTripType");
return [
...buildResponsiveRow(_buildFirstRow(isDesktop)),
// Iterate over rowBuilders based on selectedTripType
if (selectedTripType == "Oneway")
...rowBuilders.expand((row) => buildResponsiveRow(row)),
if (selectedTripType == "Roundtrip")
...rowRoundBuilders.expand((row) => buildResponsiveRow(row)),
if (selectedTripType == "Multitrip")
...List.generate(multiTripRowCount, (index) {
// List<Widget> firstRow = _builClassType(isDesktop, index + 1);
List<Widget> secondRow = _buildSecondRow(isDesktop, index + 1);
return [
// ...buildResponsiveRow(firstRow), // Row 1
...buildResponsiveRow(secondRow), // Row 2
];
}).expand((row) => row),
// if (selectedTripType == "Multitrip")
// ...List.generate(multiTripRowCount, (index) =>
// buildResponsiveRow(_builClassType(isDesktop, index + 1) + _buildSecondRow(isDesktop, index + 1))
// ).expand((row) => row),
if (selectedTripType == "Multitrip")
Align(
alignment: Alignment.centerRight,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize:
!isDesktop
? const Size.fromHeight(48)
: null, // No min height on desktop // height
backgroundColor: Colors.green,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: () {
setState(() {
multiTripRowCount++; // Increase the row count
});
// Dynamically create controllers and focus nodes for new trip fields
for (var field in dataHeader) {
String keyController = "${field}${multiTripRowCount}Controller";
String keyFocusNode = "${field}${multiTripRowCount}FocusNode";
String keyFocusState = "${field}${multiTripRowCount}Focused";
// Create TextEditingController if it doesn't exist
if (!textControllers.containsKey(keyController)) {
textControllers[keyController] = TextEditingController();
}
// Create FocusNode if it doesn't exist
if (!focusNodes.containsKey(keyFocusNode)) {
focusNodes[keyFocusNode] = FocusNode();
// Attach focus listener for dynamic fields
focusNodes[keyFocusNode]!.addListener(() {
setState(() {
focusStates[keyFocusState] =
focusNodes[keyFocusNode]!.hasFocus;
});
});
}
// Initialize focus state
focusStates[keyFocusState] = false;
}
// _initializeFields();
},
child: Text(
"Add Trip",
style: TextStyle(color: Colors.white, fontSize: 12),
),
),
),
if (selectedTripType == "Multitrip") SizedBox(height: 10),
// ...buildResponsiveRow(_buildvisa(isDesktop)),
...buildResponsiveRow(_buildThirdRow(isDesktop)),
// Actions row remains a Row
];
}
List<String> filterAndSortCountryList(List<String> items, String filter) {
final lowerFilter = filter.toLowerCase();
int getMatchScore(String item) {
final parts = item.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1].toLowerCase() : '';
final match = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode);
final city = match?.group(1)?.toLowerCase() ?? '';
final code = match?.group(2)?.toLowerCase() ?? '';
if (code == lowerFilter) return 0;
if (code.startsWith(lowerFilter)) return 1;
if (code.contains(lowerFilter)) return 2;
if (city == lowerFilter) return 3;
if (city.startsWith(lowerFilter)) return 4;
if (city.contains(lowerFilter)) return 5;
if (airport.contains(lowerFilter)) return 6;
return 999;
}
return items.where((item) {
final parts = item.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1].toLowerCase() : '';
final match = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode);
final city = match?.group(1)?.toLowerCase() ?? '';
final code = match?.group(2)?.toLowerCase() ?? '';
return code.contains(lowerFilter) ||
city.contains(lowerFilter) ||
airport.contains(lowerFilter);
}).toList()
..sort((a, b) => getMatchScore(a).compareTo(getMatchScore(b)));
}
List<Widget> _buildFirstRow(isDesktop) {
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Trip Type",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
isDesktop
? Row(children: _buildTripType(isDesktop))
: Column(children: _buildTripType(isDesktop)),
],
),
if (isDesktop) Spacer() else SizedBox(height: 8),
];
}
List<Widget> _buildTripType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
return [
CustomTextFieldWrapper(
// isFocused: _tripTypeFocused,
// isFocused: focusStates["_tripType1Focused"] ?? false,
isFocused: false,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: focusNodes["_tripType1FocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["_tripType1Focused"] = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
focusNodes["_tripType1FocusNode"]?.requestFocus();
},
child: DropdownSearch<String>(
items:
purposeList
.map((item) => item['dropdown_value'] as String)
.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_tripType1Focused"] ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_tripType1Focused"] ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
),
),
onChanged: (newValue) {
setState(() {
selectedTripType = newValue;
if (selectedTripType != "Multitrip") {
multiTripRowCount = 1;
}
errorMessages.clear();
for (int i = 1; i <= rowCount; i++) {
textControllers["_date${i}Controller"]?.clear();
textControllers["_time${i}Controller"]?.clear();
// Also clear the actual selected data (not just the text in controllers)
selectedFrom[i] =
null; // Assuming null means no selection
selectedTo[i] = null;
}
});
print(
"Updating form data: Flight -> trip_type -> $selectedTripType",
);
_initializeFields();
},
selectedItem: selectedTripType,
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select",
style: TextStyle(fontSize: 12),
),
),
popupProps: PopupProps.menu(
constraints: BoxConstraints(maxHeight: 100),
menuProps: MenuProps(backgroundColor: Colors.white),
itemBuilder:
(context, item, isSelected) => Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 6.0,
),
child: Text(
item,
style: TextStyle(
fontSize: 13,
), // Custom text size for dropdown items
),
),
),
),
),
),
),
),
];
}
List<Widget> _buildSecondRow(bool isDesktop, int index) {
return isDesktop
? [
_buildFrom(isDesktop, index),
Spacer(),
_buildTo(isDesktop, index),
Spacer(),
_buildClass(isDesktop, index),
Spacer(),
_buildDate(isDesktop, index),
Spacer(),
_buildTime(isDesktop, index),
Spacer(),
if (selectedTripType == "Multitrip")
Container(
// color: Colors.blueGrey,
// padding: const EdgeInsets.only(top: 50, bottom: 50),
child: IconButton(
onPressed: () {
removeTrip(index);
},
icon: Icon(Icons.close, color: Colors.redAccent, size: 20),
),
),
]
: [
Card(
elevation: 1,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
color: const Color(0xFFF5F5F5), // Light grey
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [
_buildFrom(isDesktop, index),
SizedBox(height: 8),
_buildTo(isDesktop, index),
SizedBox(height: 8),
_buildClass(isDesktop, index),
SizedBox(height: 8),
_buildDate(isDesktop, index),
SizedBox(height: 8),
_buildTime(isDesktop, index),
SizedBox(height: 8),
if (selectedTripType == "Multitrip")
if (multiTripRowCount > 1)
Padding(
padding: const EdgeInsets.only(top: 10),
child: SizedBox(
width: double.infinity, // ensure full width
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(
48,
), // set height
backgroundColor: Colors.red,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
onPressed: () {
print("Pressed: $index");
removeTrip(index);
},
child: const Text(
"Remove",
style: TextStyle(fontSize: 14),
),
),
),
),
if (selectedTripType == "Multitrip") SizedBox(height: 8),
],
),
),
),
];
}
Widget _buildFrom(bool isDesktop, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"From*",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
// isFocused: _fromFocus,
// isFocused: focusStates["_from${index}Focused"] ?? false,
isFocused: false,
padding: const EdgeInsets.symmetric(horizontal: 0),
// isFocused: focusStates["_from${fieldIndex}Focused"] ?? false,
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child:
isCountryLoading
? Center(child: CircularProgressIndicator())
: Focus(
focusNode: focusNodes["_from${index}FocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["_from${index}Focused"] = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
focusNodes["_from${index}FocusNode"]?.requestFocus();
},
child: DropdownSearch<String>(
enabled:
!(selectedTripType == "Roundtrip" && index == 2),
selectedItem:
selectedFrom[index] != null
? countryMap[selectedFrom[index]]
: null,
items: countryMap.values.toList(),
// asyncItems: (String filter) async {
// final allItems = countryMap.values.toSet().toList();
// print("Original items: ${allItems.length}");
// final filtered = filterAndSortCountryList(allItems, filter);
// // print("Filtered items: ${filtered.length} -> $filtered");
// return filtered;
// },
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 220),
showSearchBox: true, // Enables search functionality
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search...",
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 1,
),
),
style: TextStyle(fontSize: 12),
),
menuProps: MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
final parts = item.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
// Extract city and code from "City (CODE)"
final cityMatch = RegExp(
r'^(.*)\s+\(([^)]+)\)$',
).firstMatch(cityAndCode);
final city = cityMatch?.group(1) ?? '';
final code = cityMatch?.group(2) ?? '';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 6.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
city,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
Text(
code,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 1),
Text(
airport,
style: const TextStyle(
fontSize: 11,
color: Colors.grey,
overflow: TextOverflow.ellipsis,
),
),
],
),
);
},
// itemBuilder:
// (context, item, isSelected) => Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 8.0,
// vertical: 6.0,
// ),
// child: Text(
// item,
// style: TextStyle(
// fontSize: 13,
// ), // 👈 Set your desired text size here
// ),
// ),
),
// items: countryMap.values.toList(),
// filterFn: (item, filter) {
// final lowerFilter = filter.toLowerCase();
//
// final parts = item.split('\n');
// final cityAndCode = parts[0];
// final airport = parts.length > 1 ? parts[1].toLowerCase() : '';
//
// // Extract city and code from "City (CODE)"
// final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode);
// final city = cityMatch?.group(1)?.toLowerCase() ?? '';
// final code = cityMatch?.group(2)?.toLowerCase() ?? '';
//
// // Priority: Code > City > Airport
// return code.contains(lowerFilter) ||
// city.contains(lowerFilter) ||
// airport.contains(lowerFilter);
// },
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_from${index}Focused"] ??
false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_from${index}Focused"] ??
false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: layoutColor,
width: 1,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null) {
return Align(
alignment: Alignment.centerLeft,
child: const Text(
"Select",
style: TextStyle(fontSize: 12),
),
);
}
final parts = selectedItem.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
return Align(
alignment: Alignment.centerLeft,
child: Text(
cityAndCode ?? "Select",
style: const TextStyle(fontSize: 12),
),
);
},
// dropdownBuilder:
// (context, selectedItem) => Align(
// alignment: Alignment.centerLeft,
// child: Text(
// selectedItem ?? "Select",
// style: TextStyle(fontSize: 12),
// ),
// ),
onChanged: (String? newValue) {
setState(() {
errorMessages.remove("from_place_$index");
// selectedFrom[index] = countryMap.entries
// .firstWhere((entry) => entry.value == newValue)
// .key;
selectedFrom[index] =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
)
.key;
if (selectedTripType == "Roundtrip") {
print('rounfTo${selectedFrom[index]}');
// textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
selectedTo[2] = selectedFrom[index]!;
}
});
},
),
),
),
),
// child: SizedBox(
// height: 40,
// child: TextField(
// // focusNode: _fromFocusNode,
// focusNode: focusNodes["_from${index}FocusNode"],
// controller: textControllers["_from${index}Controller"],
// style: const TextStyle(fontSize: 12),
// decoration: const InputDecoration(
// labelText: "From",
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
// floatingLabelBehavior: FloatingLabelBehavior.never,
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(vertical: 16),
// ),
// ),
// ),
),
if (errorMessages["from_place_$index"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
errorMessages["from_place_$index"]!,
style: TextStyle(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget _buildTo(bool isDesktop, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"To*",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
// isFocused: focusStates["_to${index}Focused"] ?? false,
isFocused: false,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child:
isCountryLoading
? Center(child: CircularProgressIndicator())
: Focus(
focusNode: focusNodes["_to${index}FocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["_to${index}Focused"] = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
focusNodes["_to${index}FocusNode"]?.requestFocus();
},
child: DropdownSearch<String>(
enabled:
!(selectedTripType == "Roundtrip" && index == 2),
selectedItem:
selectedTo[index] != null
? countryMap[selectedTo[index]]
: null,
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 220),
showSearchBox: true, // Enables search functionality
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search...",
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 1,
),
),
style: TextStyle(fontSize: 12),
),
menuProps: MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
final parts = item.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
// Extract city and code from "City (CODE)"
final cityMatch = RegExp(
r'^(.*)\s+\(([^)]+)\)$',
).firstMatch(cityAndCode);
final city = cityMatch?.group(1) ?? '';
final code = cityMatch?.group(2) ?? '';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 6.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
city,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
Text(
code,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 1),
Text(
airport,
style: const TextStyle(
fontSize: 11,
color: Colors.grey,
overflow: TextOverflow.ellipsis,
),
),
],
),
);
},
// itemBuilder:
// (context, item, isSelected) => Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 8.0,
// vertical: 6.0,
// ),
// child: Text(
// item,
// style: TextStyle(
// fontSize: 13,
// ), // 👈 Set your desired text size here
// ),
// ),
),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_to${index}Focused"] ??
false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_to${index}Focused"] ??
false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: layoutColor,
width: 1,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
),
),
// dropdownBuilder:
// (context, selectedItem) => Align(
// alignment: Alignment.centerLeft,
// child: Text(
// selectedItem ?? "Select Country",
// style: TextStyle(fontSize: 12),
// ),
// ),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null) {
return Align(
alignment: Alignment.centerLeft,
child: const Text(
"Select",
style: TextStyle(fontSize: 12),
),
);
}
final parts = selectedItem.split('\n');
final cityAndCode = parts[0];
final airport = parts.length > 1 ? parts[1] : '';
return Align(
alignment: Alignment.centerLeft,
child: Text(
cityAndCode ?? "Select",
style: const TextStyle(fontSize: 12),
),
);
},
onChanged: (String? newValue) {
setState(() {
errorMessages.remove("to_place_$index");
selectedTo[index] =
countryMap.entries
.firstWhere(
(entry) => entry.value == newValue,
)
.key;
print(selectedTo[index]);
if (selectedTripType == "Roundtrip") {
print('rounfTo${selectedTo[index]}');
// textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
selectedFrom[2] = selectedTo[index]!;
}
});
},
),
),
),
),
),
if (errorMessages["to_place_$index"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
errorMessages["to_place_$index"]!,
style: TextStyle(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget _buildClass(bool isDesktop, int index) {
List<dynamic> purposeList = widget.apiDataForClass?['flight_class'] ?? [];
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Class *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
// isFocused: focusStates["_class${index}Focused"] ?? false,
isFocused: false,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: isDesktop,
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: focusNodes["_class${index}FocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["_class${index}Focused"] = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
focusNodes["_class${index}FocusNode"]?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(),
// key:
// selectedClasses[index] == null
// ? UniqueKey()
// : ValueKey(selectedClasses[index]),
// selectedItem: purposeList.firstWhere(
// (item) => item['dropdown_key'] == selectedClasses[index],
// orElse: () => {},
// ),
selectedItem:
selectedClasses[index] != null
? purposeList.firstWhere(
(item) =>
item['dropdown_key'] == selectedClasses[index],
orElse: () => {},
)
: null,
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
final bool isNotAllowed = item['is_allowed'] == 'No';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
child: Text(
item['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color:
isNotAllowed ? Colors.redAccent : Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_class${index}Focused"] ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_class${index}Focused"] ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select Class",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
);
},
onChanged:
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) async {
// if (newValue != null &&
// newValue['is_allowed'] == 'No') {
// print('not allowed');
//
// exceptionalClass[index] = "1";
// } else if (newValue != null &&
// newValue['is_allowed'] == 'yes') {
// print('not allowed');
//
// exceptionalClass[index] = "0";
// }
//
// setState(() {
// selectedClasses[index] =
// newValue?['dropdown_key'];
// print(
// "Selected Class: ${selectedClasses[index]}",
// );
// });
if (newValue != null &&
newValue['is_allowed'] == 'No') {
final confirm = await showNotAllowedDialog(
context,
message:
"You are not entitled for this service. If you wish to continue with this service, you may require another approval.",
);
if (confirm) {
setState(() {
exceptionalClass[index] = "1";
selectedClasses[index] =
newValue['dropdown_key'];
});
print(
"Selected Purpose: ${selectedClasses[index]}",
);
} else {
setState(() {
exceptionalClass[index] = "0";
selectedClasses[index] =
null; // ❌ Clear selection if user cancels
});
print(
"selectedItem resolved to: ${selectedClasses[index]}",
);
}
return;
} else if (newValue != null &&
newValue['is_allowed'] == 'yes') {
setState(() {
exceptionalClass[index] = "0";
selectedClasses[index] =
newValue?['dropdown_key'];
print(
"Selected Purpose: ${selectedClasses[index]}",
);
});
}
}
: null,
),
),
),
),
),
if (errorMessages["class_$index"] != null)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
errorMessages["class_$index"]!,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.red),
),
),
],
);
}
Widget _buildDate(bool isDesktop, int index) {
DateTime? _selectedCheckOutDate;
TimeOfDay? _selectedCheckOutTime;
Future<void> _selectCheckOutDate(BuildContext context) async {
DateTime now = DateTime.now();
DateTime today = DateTime(now.year, now.month, now.day);
// Determine the minimum date (firstDate) based on previous index if available
DateTime firstDate = today;
if (index == 1 &&
flightLastTripDateNotifier.value != null &&
flightLastTripDateNotifier.value!.isNotEmpty) {
try {
final tripDate = DateFormat(
'dd-MM-yyyy',
).parseStrict(flightLastTripDateNotifier.value!);
if (tripDate.isAfter(today)) {
firstDate = tripDate;
}
} catch (_) {
// handle parse error if needed
}
} else if (index > 1) {
final previousDateString =
textControllers["_date${index - 1}Controller"]?.text;
if (previousDateString != null && previousDateString.isNotEmpty) {
try {
final previousDate = DateFormat(
'dd-MM-yyyy',
).parseStrict(previousDateString);
if (previousDate.isAfter(today)) {
firstDate = previousDate;
}
} catch (_) {
// handle parse error if necessary
}
}
}
DateTime initialDate =
_selectedCheckOutDate != null &&
_selectedCheckOutDate!.isAfter(firstDate)
? _selectedCheckOutDate!
: firstDate;
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: initialDate,
firstDate: firstDate,
lastDate: DateTime(2100),
initialEntryMode: DatePickerEntryMode.calendarOnly,
);
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
setState(() {
_selectedCheckOutDate = pickedDate;
// _dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
textControllers["_date${index}Controller"]?.text = DateFormat(
'dd-MM-yyyy',
).format(pickedDate);
});
}
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Date*",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
isFocused: focusStates["_date${index}Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
child: SizedBox(
height: 40,
child: GestureDetector(
onTap: () {
focusNodes["_date${index}FocusNode"]?.requestFocus();
_selectCheckOutDate(context);
},
child: AbsorbPointer(
child: TextField(
focusNode: focusNodes["_date${index}FocusNode"],
// controller: _dateController,
controller: textControllers["_date${index}Controller"],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Select Date",
labelStyle: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: const Icon(
Icons.calendar_today,
size: 16,
color: Colors.grey,
),
),
),
),
),
),
),
if (errorMessages["date_$index"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
errorMessages["date_$index"]!,
style: TextStyle(color: Colors.red, fontSize: 12),
),
],
],
);
}
Widget _buildTime(bool isDesktop, int index) {
TimeOfDay? _selectedCheckOutTime;
Future<void> _selectCheckOutTime(
BuildContext context,
int index,
VoidCallback onPicked,
) async {
TimeOfDay? pickedTime = await showTimePicker(
context: context,
initialTime: _selectedCheckOutTime ?? TimeOfDay.now(),
);
if (pickedTime != null) {
final now = DateTime.now();
// Parse the selected date
final dateText = textControllers["_date${index}Controller"]?.text ?? "";
final selectedDate = DateFormat(
'dd-MM-yyyy',
).parse(dateText); // or 'yyyy-MM-dd' depending on your format
final selectedDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
pickedTime.hour,
pickedTime.minute,
);
// ✅ Only validate past time if date is today
final isToday =
selectedDate.year == now.year &&
selectedDate.month == now.month &&
selectedDate.day == now.day;
bool isPastTime = selectedDateTime.isBefore(now);
if (isToday && isPastTime) {
setState(() {
errorMessages["time_$index"] = "You can't select a past time.";
});
return;
}
// ✅ Valid time selection
setState(() {
_selectedCheckOutTime = pickedTime;
final formattedTime = DateFormat('HH:mm').format(selectedDateTime);
textControllers["_time${index}Controller"]?.text = formattedTime;
// errorMessages["time_$index"] = ""; // clear previous error
errorMessages.remove("time_$index");
onPicked(); // Trigger callback
});
}
// if (pickedTime != null && pickedTime != _selectedCheckOutTime) {
// setState(() {
// _selectedCheckOutTime = pickedTime;
// // Formatting time to HH:mm (24-hour format)
// final now = DateTime.now();
// final formattedTime = DateFormat('HH:mm').format(
// DateTime(
// now.year,
// now.month,
// now.day,
// pickedTime.hour,
// pickedTime.minute,
// ),
// );
//
// // _timeController.text = formattedTime;
// textControllers["_time${index}Controller"]?.text = formattedTime;
//
// onPicked();
// });
// }
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Time*",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
isFocused: focusStates["_time${index}Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
child: SizedBox(
height: 40,
child: GestureDetector(
onTap: () {
focusNodes["_time${index}FocusNode"]?.requestFocus();
textControllers["_time${index}Controller"]?.text = "";
_clearError("time_$index");
// validateTimeDifference(index);
// _selectCheckOutTime(context);
_selectCheckOutTime(context, index, () {
validateTimeDifference(index);
setState(
() {},
); // ✅ Force rebuild to show the error immediately
});
},
child: AbsorbPointer(
child: TextField(
focusNode: focusNodes["_time${index}FocusNode"],
// controller: _timeController,
controller: textControllers["_time${index}Controller"],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Time",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(
Icons.access_time,
size: 16,
color: Colors.grey,
),
),
),
),
// Focus(
// focusNode: focusNodes["_time${index}FocusNode"],
// onFocusChange: (hasFocus) {
// setState(() {
// focusStates["_time${index}Focused"] = hasFocus;
// });
// },
// child: GestureDetector(
// //
// onTap: () {
// // Request focus when user taps
// focusNodes["_time${index}FocusNode"]?.requestFocus();
// },
),
),
),
if (errorMessages["time_$index"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
errorMessages["time_$index"]!,
style: TextStyle(color: Colors.red, fontSize: 12),
),
],
],
);
}
List<Widget> _buildThirdRow(bool isDesktop) {
return isDesktop
? [
if (plantripType == "2") _buildVisaRequired(isDesktop),
if (plantripType == "2") SizedBox(width: 20),
_buildComments(isDesktop),
if (isDesktop) Spacer(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: _handleAction(isDesktop),
),
],
),
]
: [
if (plantripType == "2") _buildVisaRequired(isDesktop),
if (plantripType == "2") SizedBox(height: 5),
_buildComments(isDesktop),
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: _handleAction(isDesktop),
),
];
}
Widget _buildVisaRequired(bool isDesktop) {
List<dynamic> visa_available =
widget.apiData?['flight_visa_available'] ?? [];
// Default selected value
List<DropdownMenuItem<String>> dropdownItems =
visa_available
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'],
child: Text(item['dropdown_value']),
),
)
.toList();
selectedvisa_available ??=
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Visa Required",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
// use same wrapper as class
// isFocused: focusStates["_visa1Focused"] ?? false,
isFocused: false,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: isDesktop,
child: SizedBox(
height: 35,
width: double.infinity,
child: Focus(
focusNode: focusNodes["_visa1FocusNode"],
onFocusChange: (hasFocus) {
setState(() {
focusStates["_visa1Focused"] = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
focusNodes["_visa1FocusNode"]?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
items: visa_available.cast<Map<String, dynamic>>(),
selectedItem: visa_available.firstWhere(
(item) => item['dropdown_key'] == selectedvisa_available,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
child: Text(
item['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(
color:
(focusStates["_visa1Focused"] ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(focusStates["_visa1Focused"] ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select Option",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
);
},
onChanged:
visa_available.isNotEmpty
? (Map<String, dynamic>? newValue) {
setState(() {
selectedvisa_available =
newValue?['dropdown_key'];
print("Selected Visa: $selectedvisa_available");
});
}
: null,
),
),
),
),
),
],
);
}
Widget _buildComments(bool isDesktop) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Comments",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
isFocused: focusStates["_comments1Focused"] ?? false,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null,
child: TextField(
focusNode: focusNodes["_comments1FocusNode"],
// controller: _commentsController,
controller: textControllers["_comments1Controller"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
// maxLines: 6,
// keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(vertical: 1),
),
),
),
],
);
}
List<Widget> _handleAction(bool isDesktop) {
return [
// Close Button
ElevatedButton(
onPressed: () {
widget.onClose("Flight", false);
// widget.onClose(false); // Close the dialog or screen
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(
"Close",
style: GoogleFonts.poppins(color: Colors.white, fontSize: 12),
),
),
SizedBox(width: 10), // Space between buttons
// Save Changes Button
ElevatedButton(
onPressed: () {
handleSave();
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF114D8B), // Primary color for save
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(
"Save Changes",
style: GoogleFonts.poppins(color: Colors.white, fontSize: 12),
),
),
];
}
List<Widget> _buildvisa(bool isDesktop) {
List<dynamic> visa_available =
widget.apiData?['flight_visa_available'] ?? [];
// Default selected value
List<DropdownMenuItem<String>> dropdownItems =
visa_available
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'],
child: Text(item['dropdown_value']),
),
)
.toList();
selectedvisa_available ??=
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Visa Required",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
// isFocused: _tripTypeFocused,
isFocused: focusStates["_visa1Focused"] ?? false,
isDesktop: isDesktop,
// width:
// isDesktop
// ? MediaQuery.of(context).size.width * 0.34
// : MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: DropdownButtonFormField<String>(
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
focusNode: focusNodes["_visa1FocusNode"],
value: selectedvisa_available,
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
), // Proper padding
),
onChanged:
visa_available.isNotEmpty
? (newValue) {
setState(() {
selectedvisa_available = newValue;
// selectedTripType = "Oneway";
// Reset `multiTripRowCount` when switching away from Multitrip
});
print(
"Updating form data: Flight -> trip_type -> $selectedvisa_available",
);
// _initializeRows();
}
: null,
items: dropdownItems,
),
),
),
],
),
];
}
List<Widget> _buildDelete(bool isDesktop, int index) {
return [
Container(
padding: const EdgeInsets.all(10),
// padding: const EdgeInsets.only(left: 10, right: 10),
// color: Colors.white,
child: Text(
"Trip ${index}",
style: TextStyle(
fontSize: 14,
color: Colors.blueAccent,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(
width:
isDesktop
? MediaQuery.of(context).size.width * 0.58
: 80, // Ensure full width
child: Stack(
alignment: Alignment.center, // Centers the icon
children: [
Divider(color: Color(0xFF8B8FB2), thickness: 0.5, height: 20),
Container(
// padding: EdgeInsets.all(4),
color: Colors.white, // Background to avoid overlapping
child: Row(
mainAxisSize:
MainAxisSize.min, // Prevents row from taking full width
children: [
Icon(Icons.add_circle_sharp, color: Colors.blue, size: 28),
],
),
),
],
),
),
// SizedBox(
// width: isDesktop
// ? MediaQuery.of(context).size.width * 0.29
// : MediaQuery.of(context).size.width * 0.3,
// child: Stack(
// alignment: Alignment.center, // Centers the icon
// children: [
// Divider(
// color: Color(0xFF8B8FB2),
// thickness: 0.5,
// height: 20,
// ),
// Container(
// // padding: EdgeInsets.all(4),
// color: Colors.white, // Background to avoid overlapping
// child: Row(
// mainAxisSize:
// MainAxisSize.min, // Prevents row from taking full width
// children: [
// Icon(Icons.add_circle_sharp, color: Colors.blue, size: 28),
// ],
// ),
// ),
// ],
// ),
// ),
Container(
// color: Colors.white,
// padding: const EdgeInsets.only(left: 10, right: 10),
child: IconButton(
onPressed: () {
removeTrip(index);
},
icon: Icon(Icons.delete),
color: Colors.blueAccent,
iconSize: 20,
),
),
];
}
// List<Widget> _buildSecondRow1(bool isDesktop, int index) {
// bool isFlightClassLoading = widget.apiDataForClass?['flight_class'] == null;
//
// List<dynamic> purposeList = widget.apiDataForClass?['flight_class'] ?? [];
//
// List<DropdownMenuItem<String>> dropdownItems =
// purposeList
// .map(
// (item) => DropdownMenuItem<String>(
// value: item['dropdown_key'],
// child: Text(item['dropdown_value']),
// ),
// )
// .toList();
//
// if (dropdownItems.isEmpty) {
// dropdownItems.add(
// DropdownMenuItem<String>(
// value: null,
// child: Text(
// "No options available",
// style: TextStyle(color: Colors.grey),
// ),
// ),
// );
// }
//
// // Default selected value
// // selectedClasses[index] ??=
// // dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
// // -------------------------------------------------
//
// DateTime? _selectedCheckOutDate;
// TimeOfDay? _selectedCheckOutTime;
//
// Future<void> _selectCheckOutDate(BuildContext context) async {
// DateTime now = DateTime.now();
// DateTime today = DateTime(now.year, now.month, now.day);
// // Determine the minimum date (firstDate) based on previous index if available
// DateTime firstDate = today;
//
// if (index == 1 &&
// flightLastTripDateNotifier.value != null &&
// flightLastTripDateNotifier.value!.isNotEmpty) {
// try {
// final tripDate = DateFormat(
// 'dd-MM-yyyy',
// ).parseStrict(flightLastTripDateNotifier.value!);
// if (tripDate.isAfter(today)) {
// firstDate = tripDate;
// }
// } catch (_) {
// // handle parse error if needed
// }
// } else if (index > 1) {
// final previousDateString =
// textControllers["_date${index - 1}Controller"]?.text;
// if (previousDateString != null && previousDateString.isNotEmpty) {
// try {
// final previousDate = DateFormat(
// 'dd-MM-yyyy',
// ).parseStrict(previousDateString);
// if (previousDate.isAfter(today)) {
// firstDate = previousDate;
// }
// } catch (_) {
// // handle parse error if necessary
// }
// }
// }
//
// DateTime initialDate =
// _selectedCheckOutDate != null &&
// _selectedCheckOutDate!.isAfter(firstDate)
// ? _selectedCheckOutDate!
// : firstDate;
//
// DateTime? pickedDate = await showDatePicker(
// context: context,
// initialDate: initialDate,
// firstDate: firstDate,
// lastDate: DateTime(2100),
// initialEntryMode: DatePickerEntryMode.calendarOnly,
// );
//
// if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
// setState(() {
// _selectedCheckOutDate = pickedDate;
// // _dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
// textControllers["_date${index}Controller"]?.text = DateFormat(
// 'dd-MM-yyyy',
// ).format(pickedDate);
// });
// }
// }
//
// Future<void> _selectCheckOutTime(
// BuildContext context,
// int index,
// VoidCallback onPicked,
// ) async {
// TimeOfDay? pickedTime = await showTimePicker(
// context: context,
// initialTime: _selectedCheckOutTime ?? TimeOfDay.now(),
// );
//
// if (pickedTime != null) {
// final now = DateTime.now();
//
// // Parse the selected date
// final dateText = textControllers["_date${index}Controller"]?.text ?? "";
// final selectedDate = DateFormat(
// 'dd-MM-yyyy',
// ).parse(dateText); // or 'yyyy-MM-dd' depending on your format
//
// final selectedDateTime = DateTime(
// selectedDate.year,
// selectedDate.month,
// selectedDate.day,
// pickedTime.hour,
// pickedTime.minute,
// );
//
// // ✅ Only validate past time if date is today
// final isToday =
// selectedDate.year == now.year &&
// selectedDate.month == now.month &&
// selectedDate.day == now.day;
//
// bool isPastTime = selectedDateTime.isBefore(now);
//
// if (isToday && isPastTime) {
// setState(() {
// errorMessages["time_$index"] = "You can't select a past time.";
// });
// return;
// }
//
// // ✅ Valid time selection
// setState(() {
// _selectedCheckOutTime = pickedTime;
//
// final formattedTime = DateFormat('HH:mm').format(selectedDateTime);
// textControllers["_time${index}Controller"]?.text = formattedTime;
// // errorMessages["time_$index"] = ""; // clear previous error
// errorMessages.remove("time_$index");
// onPicked(); // Trigger callback
// });
// }
//
// // if (pickedTime != null && pickedTime != _selectedCheckOutTime) {
// // setState(() {
// // _selectedCheckOutTime = pickedTime;
// // // Formatting time to HH:mm (24-hour format)
// // final now = DateTime.now();
// // final formattedTime = DateFormat('HH:mm').format(
// // DateTime(
// // now.year,
// // now.month,
// // now.day,
// // pickedTime.hour,
// // pickedTime.minute,
// // ),
// // );
// //
// // // _timeController.text = formattedTime;
// // textControllers["_time${index}Controller"]?.text = formattedTime;
// //
// // onPicked();
// // });
// // }
// }
//
// return isDesktop
// ? [
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "From*",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldItnerarySubWrapper(
// // isFocused: _fromFocus,
// // isFocused: focusStates["_from${index}Focused"] ?? false,
// isFocused: false,
// padding: const EdgeInsets.symmetric(horizontal: 0),
// // isFocused: focusStates["_from${fieldIndex}Focused"] ?? false,
// isDesktop: isDesktop,
// child: SizedBox(
// height: 40,
// child:
// isCountryLoading
// ? Center(child: CircularProgressIndicator())
// : Focus(
// focusNode: focusNodes["_from${index}FocusNode"],
// onFocusChange: (hasFocus) {
// setState(() {
// focusStates["_from${index}Focused"] = hasFocus;
// });
// },
// child: GestureDetector(
// //
// onTap: () {
// // Request focus when user taps
// focusNodes["_from${index}FocusNode"]
// ?.requestFocus();
// },
// child: DropdownSearch<String>(
// enabled:
// !(selectedTripType == "Roundtrip" &&
// index == 2),
// selectedItem:
// selectedFrom[index] != null
// ? countryMap[selectedFrom[index]]
// : null,
// items: countryMap.values.toList(),
// // asyncItems: (String filter) async {
// // final allItems = countryMap.values.toSet().toList();
// // print("Original items: ${allItems.length}");
// // final filtered = filterAndSortCountryList(allItems, filter);
// // // print("Filtered items: ${filtered.length} -> $filtered");
// // return filtered;
// // },
// popupProps: PopupProps.menu(
// fit: FlexFit.loose,
// constraints: BoxConstraints(maxHeight: 220),
// showSearchBox:
// true, // Enables search functionality
// searchFieldProps: TextFieldProps(
// decoration: InputDecoration(
// hintText: "Search...",
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 1,
// ),
// ),
// style: TextStyle(fontSize: 12),
// ),
// menuProps: MenuProps(
// backgroundColor: Colors.white,
// ),
// itemBuilder: (context, item, isSelected) {
// final parts = item.split('\n');
// final cityAndCode = parts[0];
// final airport =
// parts.length > 1 ? parts[1] : '';
//
// // Extract city and code from "City (CODE)"
// final cityMatch = RegExp(
// r'^(.*)\s+\(([^)]+)\)$',
// ).firstMatch(cityAndCode);
// final city = cityMatch?.group(1) ?? '';
// final code = cityMatch?.group(2) ?? '';
//
// return Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 8.0,
// vertical: 6.0,
// ),
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// Row(
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Text(
// city,
// style: const TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.bold,
// ),
// ),
// Text(
// code,
// style: const TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.bold,
// ),
// ),
// ],
// ),
// const SizedBox(height: 1),
// Text(
// airport,
// style: const TextStyle(
// fontSize: 11,
// color: Colors.grey,
// overflow: TextOverflow.ellipsis,
// ),
// ),
// ],
// ),
// );
// },
//
// // itemBuilder:
// // (context, item, isSelected) => Padding(
// // padding: const EdgeInsets.symmetric(
// // horizontal: 8.0,
// // vertical: 6.0,
// // ),
// // child: Text(
// // item,
// // style: TextStyle(
// // fontSize: 13,
// // ), // 👈 Set your desired text size here
// // ),
// // ),
// ),
// // items: countryMap.values.toList(),
// // filterFn: (item, filter) {
// // final lowerFilter = filter.toLowerCase();
// //
// // final parts = item.split('\n');
// // final cityAndCode = parts[0];
// // final airport = parts.length > 1 ? parts[1].toLowerCase() : '';
// //
// // // Extract city and code from "City (CODE)"
// // final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode);
// // final city = cityMatch?.group(1)?.toLowerCase() ?? '';
// // final code = cityMatch?.group(2)?.toLowerCase() ?? '';
// //
// // // Priority: Code > City > Airport
// // return code.contains(lowerFilter) ||
// // city.contains(lowerFilter) ||
// // airport.contains(lowerFilter);
// // },
// dropdownDecoratorProps: DropDownDecoratorProps(
// dropdownSearchDecoration: InputDecoration(
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(8),
// borderSide: BorderSide(
// color:
// (focusStates["_from${index}Focused"] ??
// false)
// ? layoutColor!
// : Colors.white,
// width: 0.5,
// ),
// ),
// enabledBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color:
// (focusStates["_from${index}Focused"] ??
// false)
// ? layoutColor
// : Colors.white,
// // : const Color(0xFFD6D5E6),
// width: 0.5,
// // const Color(0xFFD6D5E6),
// ),
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color: layoutColor,
// width: 1,
// ),
// ),
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 5,
// ),
// ),
// ),
// dropdownBuilder: (context, selectedItem) {
// if (selectedItem == null) {
// return Align(
// alignment: Alignment.centerLeft,
// child: const Text(
// "Select",
// style: TextStyle(fontSize: 12),
// ),
// );
// }
//
// final parts = selectedItem.split('\n');
// final cityAndCode = parts[0];
// final airport =
// parts.length > 1 ? parts[1] : '';
//
// return Align(
// alignment: Alignment.centerLeft,
// child: Text(
// cityAndCode ?? "Select",
// style: const TextStyle(fontSize: 12),
// ),
// );
// },
//
// // dropdownBuilder:
// // (context, selectedItem) => Align(
// // alignment: Alignment.centerLeft,
// // child: Text(
// // selectedItem ?? "Select",
// // style: TextStyle(fontSize: 12),
// // ),
// // ),
// onChanged: (String? newValue) {
// setState(() {
// errorMessages.remove("from_place_$index");
// // selectedFrom[index] = countryMap.entries
// // .firstWhere((entry) => entry.value == newValue)
// // .key;
//
// selectedFrom[index] =
// countryMap.entries
// .firstWhere(
// (entry) =>
// entry.value == newValue,
// )
// .key;
// if (selectedTripType == "Roundtrip") {
// print('rounfTo${selectedFrom[index]}');
// // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
// selectedTo[2] = selectedFrom[index]!;
// }
// });
// },
// ),
// ),
// ),
// ),
//
// // child: SizedBox(
// // height: 40,
// // child: TextField(
// // // focusNode: _fromFocusNode,
// // focusNode: focusNodes["_from${index}FocusNode"],
// // controller: textControllers["_from${index}Controller"],
// // style: const TextStyle(fontSize: 12),
// // decoration: const InputDecoration(
// // labelText: "From",
// // labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
// // floatingLabelBehavior: FloatingLabelBehavior.never,
// // border: InputBorder.none,
// // contentPadding: EdgeInsets.symmetric(vertical: 16),
// // ),
// // ),
// // ),
// ),
// if (errorMessages["from_place_$index"] != null) ...[
// SizedBox(height: 5), // Space before error message
// Text(
// errorMessages["from_place_$index"]!,
// style: TextStyle(color: Colors.red, fontSize: 12),
// ),
// ],
// ],
// ),
// if (isDesktop) SizedBox(width: 20) else SizedBox(height: 8),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "To*",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldItnerarySubWrapper(
// // isFocused: focusStates["_to${index}Focused"] ?? false,
// isFocused: false,
// padding: const EdgeInsets.symmetric(horizontal: 0),
// isDesktop: isDesktop,
// child: SizedBox(
// height: 40,
// child:
// isCountryLoading
// ? Center(child: CircularProgressIndicator())
// : Focus(
// focusNode: focusNodes["_to${index}FocusNode"],
// onFocusChange: (hasFocus) {
// setState(() {
// focusStates["_to${index}Focused"] = hasFocus;
// });
// },
// child: GestureDetector(
// //
// onTap: () {
// // Request focus when user taps
// focusNodes["_to${index}FocusNode"]
// ?.requestFocus();
// },
// child: DropdownSearch<String>(
// enabled:
// !(selectedTripType == "Roundtrip" &&
// index == 2),
// selectedItem:
// selectedTo[index] != null
// ? countryMap[selectedTo[index]]
// : null,
// popupProps: PopupProps.menu(
// fit: FlexFit.loose,
// constraints: BoxConstraints(maxHeight: 220),
// showSearchBox:
// true, // Enables search functionality
// searchFieldProps: TextFieldProps(
// decoration: InputDecoration(
// hintText: "Search...",
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 1,
// ),
// ),
// style: TextStyle(fontSize: 12),
// ),
// menuProps: MenuProps(
// backgroundColor: Colors.white,
// ),
// itemBuilder: (context, item, isSelected) {
// final parts = item.split('\n');
// final cityAndCode = parts[0];
// final airport =
// parts.length > 1 ? parts[1] : '';
//
// // Extract city and code from "City (CODE)"
// final cityMatch = RegExp(
// r'^(.*)\s+\(([^)]+)\)$',
// ).firstMatch(cityAndCode);
// final city = cityMatch?.group(1) ?? '';
// final code = cityMatch?.group(2) ?? '';
//
// return Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 8.0,
// vertical: 6.0,
// ),
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// Row(
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Text(
// city,
// style: const TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.bold,
// ),
// ),
// Text(
// code,
// style: const TextStyle(
// fontSize: 12,
// fontWeight: FontWeight.bold,
// ),
// ),
// ],
// ),
// const SizedBox(height: 1),
// Text(
// airport,
// style: const TextStyle(
// fontSize: 11,
// color: Colors.grey,
// overflow: TextOverflow.ellipsis,
// ),
// ),
// ],
// ),
// );
// },
// // itemBuilder:
// // (context, item, isSelected) => Padding(
// // padding: const EdgeInsets.symmetric(
// // horizontal: 8.0,
// // vertical: 6.0,
// // ),
// // child: Text(
// // item,
// // style: TextStyle(
// // fontSize: 13,
// // ), // 👈 Set your desired text size here
// // ),
// // ),
// ),
// items: countryMap.values.toList(),
// dropdownDecoratorProps: DropDownDecoratorProps(
// dropdownSearchDecoration: InputDecoration(
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(8),
// borderSide: BorderSide(
// color:
// (focusStates["_to${index}Focused"] ??
// false)
// ? layoutColor!
// : Colors.white,
// width: 0.5,
// ),
// ),
// enabledBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color:
// (focusStates["_to${index}Focused"] ??
// false)
// ? layoutColor
// : Colors.white,
// // : const Color(0xFFD6D5E6),
// width: 0.5,
// // const Color(0xFFD6D5E6),
// ),
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color: layoutColor,
// width: 1,
// ),
// ),
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 5,
// ),
// ),
// ),
//
// // dropdownBuilder:
// // (context, selectedItem) => Align(
// // alignment: Alignment.centerLeft,
// // child: Text(
// // selectedItem ?? "Select Country",
// // style: TextStyle(fontSize: 12),
// // ),
// // ),
// dropdownBuilder: (context, selectedItem) {
// if (selectedItem == null) {
// return Align(
// alignment: Alignment.centerLeft,
// child: const Text(
// "Select",
// style: TextStyle(fontSize: 12),
// ),
// );
// }
//
// final parts = selectedItem.split('\n');
// final cityAndCode = parts[0];
// final airport =
// parts.length > 1 ? parts[1] : '';
//
// return Align(
// alignment: Alignment.centerLeft,
// child: Text(
// cityAndCode ?? "Select",
// style: const TextStyle(fontSize: 12),
// ),
// );
// },
// onChanged: (String? newValue) {
// setState(() {
// errorMessages.remove("to_place_$index");
// selectedTo[index] =
// countryMap.entries
// .firstWhere(
// (entry) =>
// entry.value == newValue,
// )
// .key;
//
// print(selectedTo[index]);
//
// if (selectedTripType == "Roundtrip") {
// print('rounfTo${selectedTo[index]}');
// // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
// selectedFrom[2] = selectedTo[index]!;
// }
// });
// },
// ),
// ),
// ),
// ),
// ),
// if (errorMessages["to_place_$index"] != null) ...[
// SizedBox(height: 5), // Space before error message
// Text(
// errorMessages["to_place_$index"]!,
// style: TextStyle(color: Colors.red, fontSize: 12),
// ),
// ],
// ],
// ),
// if (isDesktop) Spacer() else SizedBox(height: 8),
//
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Class *",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldItnerarySubWrapper(
// // isFocused: focusStates["_class${index}Focused"] ?? false,
// isFocused: false,
// padding: const EdgeInsets.symmetric(horizontal: 0),
// isDesktop: isDesktop,
// child: SizedBox(
// height: 40,
// width: double.infinity,
// child: Focus(
// focusNode: focusNodes["_class${index}FocusNode"],
//
// onFocusChange: (hasFocus) {
// setState(() {
// focusStates["_class${index}Focused"] = hasFocus;
// });
// },
// child: GestureDetector(
// //
// onTap: () {
// // Request focus when user taps
// focusNodes["_class${index}FocusNode"]?.requestFocus();
// },
// child: DropdownSearch<Map<String, dynamic>>(
// items: purposeList.cast<Map<String, dynamic>>(),
// key:
// selectedClasses[index] == null
// ? UniqueKey()
// : ValueKey(selectedClasses[index]),
// // selectedItem: purposeList.firstWhere(
// // (item) => item['dropdown_key'] == selectedClasses[index],
// // orElse: () => {},
// // ),
// selectedItem:
// selectedClasses[index] != null
// ? purposeList.firstWhere(
// (item) =>
// item['dropdown_key'] ==
// selectedClasses[index],
// orElse: () => {},
// )
// : null,
// itemAsString: (item) => item['dropdown_value'] ?? '',
// popupProps: PopupProps.menu(
// showSearchBox: false,
// fit: FlexFit.loose,
// menuProps: const MenuProps(
// backgroundColor: Colors.white,
// ),
// itemBuilder: (context, item, isSelected) {
// final bool isNotAllowed =
// item['is_allowed'] == 'No';
// return Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 8,
// ),
// child: Text(
// item['dropdown_value'] ?? '',
// style: GoogleFonts.poppins(
// fontSize: 12,
// color:
// isNotAllowed
// ? Colors.redAccent
// : Colors.black,
// ),
// ),
// );
// },
// ),
// dropdownDecoratorProps: DropDownDecoratorProps(
// dropdownSearchDecoration: InputDecoration(
// // border: InputBorder.none,
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(8),
// borderSide: BorderSide(
// color:
// (focusStates["_class${index}Focused"] ??
// false)
// ? layoutColor!
// : Colors.white,
// width: 0.5,
// ),
// ),
// enabledBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color:
// (focusStates["_class${index}Focused"] ??
// false)
// ? layoutColor
// : Colors.white,
// // : const Color(0xFFD6D5E6),
// width: 0.5,
// // const Color(0xFFD6D5E6),
// ),
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(
// color: layoutColor,
// width: 1,
// ),
// ),
// contentPadding: const EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 5,
// ),
// ),
// ),
// dropdownBuilder: (context, selectedItem) {
// if (selectedItem == null || selectedItem.isEmpty) {
// return Text(
// "Select Class",
// style: GoogleFonts.poppins(
// color: Colors.grey,
// fontSize: 13,
// ),
// );
// }
// return Text(
// selectedItem['dropdown_value'] ?? '',
// style: GoogleFonts.poppins(
// fontSize: 12,
// color: Colors.black,
// ),
// );
// },
// onChanged:
// purposeList.isNotEmpty
// ? (Map<String, dynamic>? newValue) async {
// // if (newValue != null &&
// // newValue['is_allowed'] == 'No') {
// // print('not allowed');
// //
// // exceptionalClass[index] = "1";
// // } else if (newValue != null &&
// // newValue['is_allowed'] == 'yes') {
// // print('not allowed');
// //
// // exceptionalClass[index] = "0";
// // }
// //
// // setState(() {
// // selectedClasses[index] =
// // newValue?['dropdown_key'];
// // print(
// // "Selected Class: ${selectedClasses[index]}",
// // );
// // });
//
// if (newValue != null &&
// newValue['is_allowed'] == 'No') {
// final confirm = await showNotAllowedDialog(
// context,
// message:
// "You are not entitled for this service. If you wish to continue with this service, you may require another approval.",
// );
//
// if (confirm) {
// setState(() {
// exceptionalClass[index] = "1";
// selectedClasses[index] =
// newValue['dropdown_key'];
// });
// print(
// "Selected Purpose: ${selectedClasses[index]}",
// );
// } else {
// setState(() {
// exceptionalClass[index] = "0";
// selectedClasses[index] =
// null; // ❌ Clear selection if user cancels
// });
// print(
// "selectedItem resolved to: ${selectedClasses[index]}",
// );
// }
//
// return;
// } else if (newValue != null &&
// newValue['is_allowed'] == 'yes') {
// setState(() {
// exceptionalClass[index] = "0";
// selectedClasses[index] =
// newValue?['dropdown_key'];
// print(
// "Selected Purpose: ${selectedClasses[index]}",
// );
// });
// }
// }
// : null,
// ),
// ),
// ),
// ),
// ),
// if (errorMessages["class_$index"] != null)
// Padding(
// padding: const EdgeInsets.only(top: 4),
// child: Text(
// errorMessages["class_$index"]!,
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.red),
// ),
// ),
// ],
// ),
// if (isDesktop) Spacer() else SizedBox(height: 8),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Date*",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldItnerarySubWrapper(
// isFocused: focusStates["_date${index}Focused"] ?? false,
//
// isDesktop: isDesktop,
// width:
// isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
// child: SizedBox(
// height: 40,
// child: GestureDetector(
// onTap: () {
// focusNodes["_date${index}FocusNode"]?.requestFocus();
// _selectCheckOutDate(context);
// },
// child: AbsorbPointer(
// child: TextField(
// focusNode: focusNodes["_date${index}FocusNode"],
// // controller: _dateController,
// controller: textControllers["_date${index}Controller"],
// readOnly: true,
// style: const TextStyle(fontSize: 12),
// decoration: InputDecoration(
// labelText: "Select Date",
// labelStyle: const TextStyle(
// fontSize: 12,
// color: Colors.grey,
// ),
// floatingLabelBehavior: FloatingLabelBehavior.never,
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(vertical: 16),
// // border: OutlineInputBorder(
// // borderRadius: BorderRadius.circular(8),
// // borderSide: BorderSide(
// // color:
// // (focusStates["_date${index}Focused"] ?? false)
// // ? layoutColor!
// // : Colors.white,
// // width: 0.5,
// // ),
// // ),
// // enabledBorder: OutlineInputBorder(
// // borderSide: BorderSide(
// // color:
// // (focusStates["_date${index}Focused"] ?? false)
// // ? layoutColor
// // : Colors.white,
// // // : const Color(0xFFD6D5E6),
// // width: 0.5,
// // // const Color(0xFFD6D5E6),
// // ),
// // ),
// // focusedBorder: OutlineInputBorder(
// // borderSide: BorderSide(color: layoutColor, width: 1),
// // ),
// // contentPadding: const EdgeInsets.symmetric(
// // horizontal: 10,
// // vertical: 5,
// // ),
// suffixIcon: const Icon(
// Icons.calendar_today,
// size: 16,
// color: Colors.grey,
// ),
// ),
// ),
// ),
// ),
// ),
// ),
// if (errorMessages["date_$index"] != null) ...[
// SizedBox(height: 5), // Space before error message
// Text(
// errorMessages["date_$index"]!,
// style: TextStyle(color: Colors.red, fontSize: 12),
// ),
// ],
// ],
// ),
// if (isDesktop) Spacer() else SizedBox(height: 8),
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Time*",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldItnerarySubWrapper(
// isFocused: focusStates["_time${index}Focused"] ?? false,
// isDesktop: isDesktop,
// width:
// isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
// child: SizedBox(
// height: 40,
// child: GestureDetector(
// onTap: () {
// focusNodes["_time${index}FocusNode"]?.requestFocus();
// textControllers["_time${index}Controller"]?.text = "";
// _clearError("time_$index");
// // validateTimeDifference(index);
// // _selectCheckOutTime(context);
//
// _selectCheckOutTime(context, index, () {
// validateTimeDifference(index);
// setState(
// () {},
// ); // ✅ Force rebuild to show the error immediately
// });
// },
//
// child: AbsorbPointer(
// child: TextField(
// focusNode: focusNodes["_time${index}FocusNode"],
// // controller: _timeController,
// controller: textControllers["_time${index}Controller"],
// readOnly: true,
// style: const TextStyle(fontSize: 12),
// decoration: const InputDecoration(
// labelText: "Time",
// labelStyle: TextStyle(
// fontSize: 12,
// color: Colors.grey,
// ),
// floatingLabelBehavior: FloatingLabelBehavior.never,
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(vertical: 16),
// suffixIcon: Icon(
// Icons.access_time,
// size: 16,
// color: Colors.grey,
// ),
// ),
// ),
// ),
// // Focus(
// // focusNode: focusNodes["_time${index}FocusNode"],
// // onFocusChange: (hasFocus) {
// // setState(() {
// // focusStates["_time${index}Focused"] = hasFocus;
// // });
// // },
// // child: GestureDetector(
// // //
// // onTap: () {
// // // Request focus when user taps
// // focusNodes["_time${index}FocusNode"]?.requestFocus();
// // },
// ),
// ),
// ),
// if (errorMessages["time_$index"] != null) ...[
// SizedBox(height: 5), // Space before error message
// Text(
// errorMessages["time_$index"]!,
// style: TextStyle(color: Colors.red, fontSize: 12),
// ),
// ],
// ],
// ),
// if (selectedTripType == "Multitrip")
// Container(
// // color: Colors.blueGrey,
// // padding: const EdgeInsets.only(top: 50, bottom: 50),
// child: IconButton(
// onPressed: () {
// removeTrip(index);
// },
// icon: Icon(Icons.close, color: Colors.redAccent, size: 20),
// ),
// ),
// ]
// : [
// // For mobile, wrap inside a card with padding and grey background
// Card(
// elevation: 1,
// margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
// color: const Color(0xFFF5F5F5), // Light grey
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(12),
// ),
// child: Padding(
// padding: const EdgeInsets.all(12),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// if (isDesktop) SizedBox(width: 20) else SizedBox(height: 8),
//
// if (isDesktop) Spacer() else SizedBox(height: 8),
//
// if (isDesktop) Spacer() else SizedBox(height: 8),
//
// if (isDesktop) Spacer() else SizedBox(height: 8),
//
// if (selectedTripType == "Multitrip")
// if (multiTripRowCount > 1)
// Padding(
// padding: const EdgeInsets.only(top: 10),
// child: SizedBox(
// width: double.infinity, // ensure full width
// child: ElevatedButton(
// style: ElevatedButton.styleFrom(
// minimumSize: const Size.fromHeight(
// 48,
// ), // set height
// backgroundColor: Colors.red,
// foregroundColor: Colors.white,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(8),
// ),
// ),
// onPressed: () {
// print("Pressed: $index");
// removeTrip(index);
// },
// child: const Text(
// "Remove",
// style: TextStyle(fontSize: 14),
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ];
// }
}