import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.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 Map? apiData; final String? loginUser; final Function(bool) onClose; final Function(Map) onSaveFlight; final Map? selectedItem; FlightScreen({ required this.apiData,required this.loginUser, required this.onClose, required this.onSaveFlight,required this.selectedItem}); @override _FlightScreenState createState() => _FlightScreenState(); } class _FlightScreenState extends State { final GlobalKey _formKey = GlobalKey(); Map selectedValues = {}; String? selectedTripType; Map selectedClasses = {}; // Store class selection for each trip String? selectedvisa_available; int multiTripRowCount = 1; List dataHeader = ["_tripType", "_class", "_from", "_to", "_date","_visa", "_time", "_comments"]; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map fieldErrors = {}; // Holds error messages List> rowBuilders = []; // Holds row widgets List controllers = []; // Dynamic controllers Map errorMessages = {}; @override void initState() { super.initState(); // _initializeRows(); // List 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 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")); } } int getRowCount() { if (selectedTripType == "RoundTrip") { return 2; } else if (selectedTripType == "Multitrip") { return multiTripRowCount; } return 1; // Default for Oneway } 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 get flightsData{ List> 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++) { 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 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 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; int index = i + 1; // Use 1-based indexing to match the form selectedClasses[index] = trip["class"].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"]); } 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); print("FlightData - $flightsData"); } bool validateFields() { errorMessages.clear(); // Reset errors 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 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 (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["_time${i}Controller"]?.text.trim().isEmpty ?? true) { errorMessages["time_$i"] = "Required"; } } 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 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 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 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), child: Form( key: _formKey, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Align( alignment: Alignment.centerRight, child: InkWell( onTap: () { widget.onClose(false); }, child: Icon( Icons.close, size: 18, color: Color(0xFF575A74), ), ), ), Text("Flight Booking", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))), SizedBox( height: 6, ), Padding( padding: const EdgeInsets.all(28.0), child: Center( child: Column(children: _buildAccomadtionForm(isDesktop)), ), ) ], ), ), ), ); }); } // void _addNewRow() { // setState(() { // rowBuilders.add(_builClassType(false)); // controllers.add(TextEditingController()); // }); // } List _buildAccomadtionForm (bool isDesktop) { List buildResponsiveRow(List children) { return [ isDesktop ? Row(children: children) : Column(children: children), SizedBox(height: 10), ]; } List> rowBuilders = [ _builClassType(isDesktop,1), _buildSecondRow(isDesktop,1) ]; List> 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 firstRow = _builClassType(isDesktop, index + 1); List 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( backgroundColor: Colors.blueAccent, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: Colors.blueAccent, width: 2), ), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2), ) , 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(fontSize: 10,fontWeight:FontWeight.bold),), ), ), ...buildResponsiveRow(_buildvisa(isDesktop)), ...buildResponsiveRow(_buildThirdRow(isDesktop)), // Actions row remains a Row Row( mainAxisAlignment: MainAxisAlignment.end, children: _handleAction(isDesktop), ), ]; } List _buildFirstRow(isDesktop) { return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Trip Type", style: TextStyle( 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 _buildTripType(bool isDesktop){ List purposeList = widget.apiData?['flight_trip_type'] ?? []; List> dropdownItems = purposeList .map((item)=>DropdownMenuItem( value: item['dropdown_value'], child: Text(item['dropdown_value']), )).toList(); if (dropdownItems.isEmpty) { dropdownItems.add( DropdownMenuItem( value: null, child: Text("No options available", style: TextStyle(color: Colors.grey)), ), ); } return [ CustomTextFieldWrapper( // isFocused: _tripTypeFocused, isFocused: focusStates["_tripType1Focused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, child: DropdownButtonFormField( // focusNode: _tripTypeFocusNode, // Assign the correct focus node focusNode: focusNodes["_tripType1FocusNode"], value: selectedTripType, style: TextStyle(fontSize: 12), decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.symmetric( horizontal: 10), // Proper padding ), onChanged: purposeList.isNotEmpty ? (newValue) { setState(() { selectedTripType = newValue; // selectedTripType = "Oneway"; // Reset `multiTripRowCount` when switching away from Multitrip if (selectedTripType != "Multitrip") { multiTripRowCount = 1; } errorMessages.clear(); }); print("Updating form data: Flight -> trip_type -> $selectedTripType"); _initializeFields(); // _initializeRows(); } : null, items: dropdownItems, ), ), ), ]; } List _buildDelete(bool isDesktop, int index){ return [ Align( alignment: Alignment.center, child: Text( "Trip ${index}", style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), ), SizedBox( width: isDesktop? 1000 : 80, // Ensure full width child: Divider( thickness: 1, // Make it more visible ), ), IconButton(onPressed: (){ removeTrip(index); }, icon: Icon(Icons.delete),color: Colors.red,iconSize: 20,) ]; } List _builClassType(bool isDesktop, int index){ List purposeList = widget.apiData?['flight_class'] ?? []; List> dropdownItems = purposeList .map((item)=>DropdownMenuItem( value: item['dropdown_key'], child: Text(item['dropdown_value']), )).toList(); if (dropdownItems.isEmpty) { dropdownItems.add( DropdownMenuItem( value: null, child: Text("No options available", style: TextStyle(color: Colors.grey)), ), ); } // Default selected value selectedClasses[index] ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null; return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (selectedTripType == "Multitrip" ) isDesktop? SizedBox( width: MediaQuery.of(context).size.width * 0.89, child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [..._buildDelete(isDesktop, index)]), ) : Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [..._buildDelete(isDesktop, index)]), SizedBox(height: 20), Text( "Class $index *", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: focusStates["_class${index}Focused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, child: DropdownButtonFormField( focusNode: focusNodes["_class${index}FocusNode"], // focusNode: _tripTypeFocusNode, // Assign the correct focus node // controller: _hotelNameController, value: selectedClasses[index] , style: TextStyle(fontSize: 12), decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.symmetric( horizontal: 10), // Proper padding ), onChanged: purposeList.isNotEmpty ? (newValue) { setState(() { selectedClasses[index] = newValue; }); print( selectedClasses[index] ); } : null, items: dropdownItems, ), ), ), ], ), ]; } List _buildSecondRow(bool isDesktop, int index) { DateTime? _selectedCheckOutDate; TimeOfDay? _selectedCheckOutTime; Future _selectCheckOutDate(BuildContext context) async { DateTime now = DateTime.now(); DateTime today = DateTime(now.year, now.month, now.day); DateTime? pickedDate = await showDatePicker( context: context, initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today) ? _selectedCheckOutDate! : today, firstDate: today, lastDate: DateTime(2100), ); if (pickedDate != null && pickedDate != _selectedCheckOutDate) { setState(() { _selectedCheckOutDate = pickedDate; // _dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate); textControllers["_date${index}Controller"]?.text = DateFormat('yyyy-MM-dd').format(pickedDate); }); } } Future _selectCheckOutTime(BuildContext context) async { TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: _selectedCheckOutTime ?? TimeOfDay.now(), ); 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; }); } } return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "From", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( // isFocused: _fromFocus, isFocused: focusStates["_from${index}Focused"] ?? false, // isFocused: focusStates["_from${fieldIndex}Focused"] ?? false, isDesktop: isDesktop, 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( "Required", style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), if (isDesktop) Spacer() else SizedBox( height: 8, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "To", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: focusStates["_to${index}Focused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, child: TextField( focusNode: focusNodes["_to${index}FocusNode"], controller: textControllers["_to${index}Controller"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "To", labelStyle: TextStyle(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), ), ), ), ), if (errorMessages["to_place_$index"] != null) ...[ SizedBox(height: 5), // Space before error message Text( "Required", style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), if (isDesktop) Spacer() else SizedBox( height: 8, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Date", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: focusStates["_date${index}Focused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, child: GestureDetector( onTap: () => _selectCheckOutDate(context), child: AbsorbPointer( child: TextField( focusNode: focusNodes["_date${index}FocusNode"], // controller: _dateController, controller: textControllers["_date${index}Controller"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select Date", labelStyle: TextStyle(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), suffixIcon: Icon(Icons.calendar_today, size: 16, color: Colors.grey), ), ), ), ), ), ), if (errorMessages["date_$index"] != null) ...[ SizedBox(height: 5), // Space before error message Text( "Required", style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), if (isDesktop) Spacer() else SizedBox( height: 8, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Time", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: focusStates["_timeFocused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, child: GestureDetector( onTap: () => _selectCheckOutTime(context), child: AbsorbPointer( child: TextField( focusNode: focusNodes["_time${index}FocusNode"], // controller: _timeController, controller: textControllers["_time${index}Controller"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select 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), ), ), ), ), ), ), if (errorMessages["time_$index"] != null) ...[ SizedBox(height: 5), // Space before error message Text( "Required", style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), ]; } List _buildThirdRow(bool isDesktop) { return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Comments", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: focusStates["_comments1Focused"] ?? false, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.66, child: TextField( focusNode: focusNodes["_comments1FocusNode"], // controller: _commentsController, controller: textControllers["_comments1Controller"], maxLines: 6, keyboardType: TextInputType.multiline, style: TextStyle(fontSize: 12), decoration: InputDecoration( labelText: "Description", labelStyle: TextStyle(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 4), ), ), ), ], ) ]; } List _buildvisa(bool isDesktop){ List visa_available = widget.apiData?['flight_visa_available'] ?? []; // Default selected value List> dropdownItems = visa_available .map((item)=>DropdownMenuItem( value: item['dropdown_key'], child: Text(item['dropdown_value']), )).toList(); selectedvisa_available ??= dropdownItems.isNotEmpty ? dropdownItems.first.value : null; if (dropdownItems.isEmpty) { dropdownItems.add( DropdownMenuItem( 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), CustomTextFieldWrapper( // isFocused: _tripTypeFocused, isFocused: focusStates["_visa1Focused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, child: DropdownButtonFormField( // 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 _handleAction(bool isDesktop) { return [ // Close Button ElevatedButton( onPressed: () { 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: TextStyle(color: Colors.white, fontSize: 14), ), ), SizedBox(width: 10), // Space between buttons // Save Changes Button ElevatedButton( onPressed: () { handleSave(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, // Primary color for save shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), child: Text( "Save Changes", style: TextStyle(color: Colors.white, fontSize: 14), ), ), ]; } }