import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../widgets/custom_confirmation_dialog.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; class TrainScreen extends StatefulWidget { final Map? apiData; final Map? apiDataForClass; final Function(Map) onSavetrain; final Function(String, bool) onClose; final Map? selectedItem; final String? loginUser; final String? tripType; TrainScreen({ required this.onClose, this.apiData, required this.onSavetrain, required this.selectedItem, required this.loginUser, this.apiDataForClass, this.tripType, }); @override _TrainScreenState createState() => _TrainScreenState(); } class _TrainScreenState extends State { final GlobalKey _formKey = GlobalKey(); ApiService apiService = ApiService(); bool isCountryLoading = true; Map countryMap = {}; // <--- instead of late late List countryCodes; Map selectedValues = {}; final FocusNode _trainNoFocusNode = FocusNode(); final FocusNode _typeOfClassFocusNode = FocusNode(); final FocusNode _fromFocusNode = FocusNode(); final FocusNode _toFocusNode = FocusNode(); final FocusNode _dateFocusNode = FocusNode(); final FocusNode _timeFocusNode = FocusNode(); final FocusNode _commentsFocusNode = FocusNode(); late TextEditingController _trainNoController = TextEditingController(); late TextEditingController _hotelNameController = TextEditingController(); late TextEditingController _fromController = TextEditingController(); late TextEditingController _toController = TextEditingController(); late TextEditingController _dateController = TextEditingController(); late TextEditingController _timeController = TextEditingController(); late TextEditingController _trainCommentsController = TextEditingController(); bool _trainNoFocused = false; bool _typeOfClassFocus = false; bool _fromFocus = false; bool _toFocus = false; bool _dateFocus = false; bool _timeFocus = false; bool _commentsFocus = false; String? selectedClass; String? exceptionalClass = "0"; String? selectedFrom; String? selectedTo; Color layoutColor = Colors.grey; Map errorMessages = {}; Map get trainData { Map data = { "train_no": _trainNoController.text, "class": selectedClass, "from_station": selectedFrom, // "from_station": _fromController.text, "to_station": selectedTo, // "to_station": _toController.text, "is_this_exceptional": exceptionalClass, "date": _dateController.text, "time": _timeController.text, "comments": _trainCommentsController.text, "created_by": widget.loginUser, "updated_by": widget.loginUser, }; if (widget.selectedItem != null) { if (widget.selectedItem?["indx"] != null && widget.selectedItem?["indx"] != 0) { data["indx"] = widget.selectedItem!["indx"]; } else if (widget.selectedItem?["train_id"] != null && widget.selectedItem?["train_id"] != 0) { data["train_id"] = widget.selectedItem!["train_id"]; } } return data; } TextEditingController initController(String key) { return TextEditingController(text: widget.selectedItem?[key] ?? ""); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { loadInitialData(); }); _trainNoFocusNode.addListener(() { setState(() { _trainNoFocused = _trainNoFocusNode.hasFocus; }); }); _typeOfClassFocusNode.addListener(() { setState(() { _typeOfClassFocus = _typeOfClassFocusNode.hasFocus; }); }); _fromFocusNode.addListener(() { setState(() { _fromFocus = _fromFocusNode.hasFocus; }); }); _toFocusNode.addListener(() { setState(() { _toFocus = _toFocusNode.hasFocus; }); }); _dateFocusNode.addListener(() { setState(() { _dateFocus = _dateFocusNode.hasFocus; }); }); _timeFocusNode.addListener(() { setState(() { _timeFocus = _timeFocusNode.hasFocus; }); }); _commentsFocusNode.addListener(() { setState(() { _commentsFocus = _commentsFocusNode.hasFocus; }); }); _trainCommentsController = initController("comments"); _trainNoController = initController("train_no"); // _fromController = initController("from_station"); _toController = initController("to_station"); _dateController = initController("date"); _timeController = initController("time"); if (widget.selectedItem != null && widget.selectedItem!["is_this_exceptional"] != null) { exceptionalClass = widget.selectedItem!["is_this_exceptional"].toString(); } // Set the selected value if available if (widget.selectedItem != null && widget.selectedItem!["class"] != null) { selectedClass = widget.selectedItem!["class"].toString(); } // if (widget.selectedItem != null && // widget.selectedItem!["from_station"] != null) { // final fromCode = widget.selectedItem!["from_station"].toString(); // if (countryMap.containsKey(fromCode)) { // selectedFrom = fromCode; // } // } if (widget.selectedItem != null && widget.selectedItem!["from_station"] != null) { selectedFrom = widget.selectedItem!["from_station"].toString(); print("Selected From CODE = $selectedFrom"); } if (widget.selectedItem != null && widget.selectedItem!["to_station"] != null) { selectedTo = widget.selectedItem!["to_station"].toString(); print("Selected To CODE = $selectedTo"); } // if (widget.selectedItem != null && // widget.selectedItem!["from_station"] != null) { // String fromPlaceDisplay = widget.selectedItem!["from_station"].toString(); // // selectedFrom = countryMap.entries // .firstWhere((entry) => entry.value == fromPlaceDisplay, // orElse: () => MapEntry('', '')) // avoid crash if not found // .key; // // print("Selected From CODE = $selectedFrom"); // } // if (widget.selectedItem != null && // widget.selectedItem!["to_station"] != null) { // selectedClass = widget.selectedItem!["to_station"].toString(); // } _trainNoController.addListener(() => _clearError("train_no")); // _fromController.addListener(() => _clearError("from_station")); _toController.addListener(() => _clearError("to_station")); _dateController.addListener(() => _clearError("date")); _timeController.addListener(() => _clearError("time")); loadCountryList(); } @override void dispose() { _trainNoFocusNode.dispose(); _dateFocusNode.dispose(); _timeFocusNode.dispose(); _typeOfClassFocusNode.dispose(); _fromFocusNode.dispose(); _toFocusNode.dispose(); _commentsFocusNode.dispose(); _trainNoController.dispose(); _hotelNameController.dispose(); _fromController.dispose(); _toController.dispose(); _dateController.dispose(); _timeController.dispose(); _trainCommentsController.dispose(); super.dispose(); } void loadInitialData() async { String? layoutString = await getLayoutColor(); setState(() { layoutColor = layoutString != null ? Color(int.parse(layoutString)) : Colors.redAccent; }); } void _clearError(String field) { if (mounted && errorMessages.containsKey(field)) { setState(() { errorMessages.remove(field); }); } } bool isValidData(Map data) { errorMessages.clear(); // Reset errors // Required fields that must not be empty List requiredFields = [ "train_no", "class", "from_station", "to_station", "date", "time", ]; // Check validation for each field for (String field in requiredFields) { if (data[field] == null || data[field].toString().trim().isEmpty) { errorMessages[field] = "Required"; } } if (selectedFrom == selectedTo) { errorMessages["to_station"] = "Change Destination"; } print("Error: to_place -> Change Destination (selectedFrom == selectedTo)"); return errorMessages.isEmpty; // Valid if there are no errors } Future loadCountryList() async { setState(() { isCountryLoading = true; }); final result = await apiService.fetchTrainCountryList(); print("ResultCountry : $result"); // Create a map: Country_Code -> "City, Airport" Map tempCountryMap = {}; for (var country in result) { String displayName = '${country['Station_Name']} '; tempCountryMap[country['Station_Code']] = displayName; } setState(() { countryMap = tempCountryMap; // Update the map isCountryLoading = false; }); } void handleSave() { print("Handle Save accomadationData $trainData"); Map data = trainData; if (!isValidData(data)) { print("Validation Failed: Required fields are missing."); setState(() {}); return; // Stop execution if validation fails } else { widget.onSavetrain(trainData); } widget.onClose("Train", false); // widget.onClose(false); // Close screen after saving } @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("Train Booking List", // style: TextStyle( // fontSize: 18, // fontWeight: FontWeight.bold, // color: Color(0xFF575A74))), // SizedBox( // height: 6, // ), Padding( padding: const EdgeInsets.only(top: 30.0), child: Center( child: Column(children: _buildAccomadtionForm(isDesktop)), ), ), ], ), ), ), ); }, ); } List _buildAccomadtionForm(bool isDesktop) { List buildResponsiveRow(List children) { return [ isDesktop ? Row(children: children) : Column(children: children), SizedBox(height: 10), ]; } List> rowBuilders = [ _builClassType(isDesktop), _buildSecondRow(isDesktop), ]; return [ ...buildResponsiveRow(_buildFirstRow(isDesktop)), // Iterate over rowBuilders and wrap each in a responsive container ...rowBuilders.expand((row) => buildResponsiveRow(row)), ...buildResponsiveRow(_buildThirdRow(isDesktop)), // Actions row remains a Row ]; } List _buildFirstRow(isDesktop) { return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Train Number *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFF575A74), ), ), SizedBox(height: 5), isDesktop ? Row(children: _buildTripType(isDesktop)) : Column(children: _buildTripType(isDesktop)), if (errorMessages["train_no"] != null) ...[ SizedBox(height: 5), // Space before error message Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)), ], ], ), 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), ), ), ); } // Default selected value String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null; return [ CustomTextFieldItnerarySubWrapper( isFocused: _trainNoFocused, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null, child: SizedBox( height: 40, child: TextField( focusNode: _trainNoFocusNode, controller: _trainNoController, style: TextStyle(fontSize: 12), decoration: InputDecoration( labelText: "Train number", labelStyle: TextStyle(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), ), ), ), ), ]; } List _builClassType(bool isDesktop) { return []; } List _buildSecondRow(bool isDesktop) { 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), initialEntryMode: DatePickerEntryMode.calendarOnly, ); if (pickedDate != null && pickedDate != _selectedCheckOutDate) { setState(() { _selectedCheckOutDate = pickedDate; _dateController.text = DateFormat('dd-MM-yyyy').format(pickedDate); }); } } Future _selectCheckOutTime(BuildContext context) async { TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: _selectedCheckOutTime ?? TimeOfDay.now(), ); if (pickedTime != null) { final now = DateTime.now(); // Parse the selected date final dateText = _dateController.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"] = "You can't select a past time."; }); return; } // ✅ Valid time selection setState(() { _selectedCheckOutTime = pickedTime; final formattedTime = DateFormat('HH:mm').format(selectedDateTime); _timeController.text = formattedTime; // errorMessages["time_$index"] = ""; // clear previous error errorMessages.remove("time"); }); } // 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; // }); // } } //---------------------------------------------- List purposeList = widget.apiDataForClass?['train_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 // selectedClass ??= // dropdownItems.isNotEmpty ? dropdownItems.first.value : null; return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Class *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFF575A74), ), ), SizedBox(height: 5), // CustomTextFieldItnerarySubWrapper( // isFocused: _isHotelNameFocused, // isDesktop: isDesktop, // // width: isDesktop // // ? MediaQuery.of(context).size.width * 0.34 // // : MediaQuery.of(context).size.width * 0.66, // child: SizedBox( // height: 40, // child: DropdownButtonFormField( // focusNode: _hotelNameFocusNode, // Assign the correct focus node // // controller: _hotelNameController, // value: selectedClass, // style: TextStyle(fontSize: 12), // decoration: InputDecoration( // border: InputBorder.none, // contentPadding: EdgeInsets.symmetric( // horizontal: 10, // ), // Proper padding // ), // onChanged: // purposeList.isNotEmpty // ? (newValue) { // setState(() { // selectedClass = newValue; // }); // } // : null, // items: dropdownItems, // ), // ), // ), // CustomTextFieldWrapper CustomTextFieldItnerarySubWrapper( isFocused: _typeOfClassFocus, padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, child: SizedBox( height: 40, width: double.infinity, child: Focus( focusNode: _typeOfClassFocusNode, onFocusChange: (hasFocus) { setState(() { _typeOfClassFocus = hasFocus; }); }, child: GestureDetector( onTap: () { _typeOfClassFocusNode?.requestFocus(); }, child: DropdownSearch>( key: selectedClass == null ? UniqueKey() : ValueKey(selectedClass), items: purposeList.cast>(), // selectedItem: purposeList.firstWhere( // (item) => item['dropdown_key'] == selectedClass, // orElse: () => {}, // ), selectedItem: selectedClass != null ? purposeList.firstWhere( (item) => item['dropdown_key'] == selectedClass, 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: 5, ), 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(5), borderSide: BorderSide( color: (_typeOfClassFocus ?? false) ? layoutColor! : Colors.white, width: 1, ), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: (_typeOfClassFocus ?? false) ? layoutColor : Colors.white, // : const Color(0xFFD6D5E6), width: 1, // const Color(0xFFD6D5E6), ), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: layoutColor, width: 1), ), contentPadding: EdgeInsets.symmetric( horizontal: 10, vertical: 10, ), ), ), dropdownBuilder: (context, selectedItem) { if (selectedItem == null || selectedItem.isEmpty) { return Text( "Select ", 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? newValue) async { 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 = "1"; selectedClass = newValue['dropdown_key']; }); print("Selected Purpose: ${selectedClass}"); } else { setState(() { exceptionalClass = "0"; selectedClass = null; // ❌ Clear selection if user cancels }); print( "selectedItem resolved to: ${selectedClass}", ); } return; } else if (newValue != null && newValue['is_allowed'] == 'yes') { setState(() { exceptionalClass = "0"; selectedClass = newValue?['dropdown_key']; print("Selected Purpose: ${selectedClass}"); }); } // if (newValue != null && // newValue['is_allowed'] == 'No') { // print('not allowed'); // // setState(() { // exceptionalClass = "1"; // // hasExceptionalClass = true; // }); // } setState(() { selectedClass = newValue?['dropdown_key']; print("Selected Purpose: ${selectedClass}"); }); } : null, ),),) ), ), if (errorMessages["class"] != 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( "From *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFF575A74), ), ), SizedBox(height: 5), // CustomTextFieldItnerarySubWrapper( // isFocused: _fromFocus, // isDesktop: isDesktop, // child: SizedBox( // height: 40, // child: // isCountryLoading // ? Center(child: CircularProgressIndicator()) // : DropdownSearch( // // selectedItem: selectedFrom != null // // ? countryMap[selectedFrom] // // : null, // selectedItem: // selectedFrom != null // ? countryMap[selectedFrom] // get the display value from code // : null, // popupProps: PopupProps.menu( // menuProps: MenuProps(backgroundColor: Colors.white), // constraints: BoxConstraints(maxHeight: 230), // showSearchBox: true, // searchFieldProps: TextFieldProps( // decoration: InputDecoration( // hintText: "Search ...", // contentPadding: EdgeInsets.symmetric( // horizontal: 10, // ), // ), // ), // ), // // items: countryMap.values.toList(), // // dropdownDecoratorProps: DropDownDecoratorProps( // dropdownSearchDecoration: InputDecoration( // contentPadding: EdgeInsets.symmetric( // horizontal: 10, // vertical: 5, // ), // border: InputBorder.none, // ), // ), // dropdownBuilder: // (context, selectedItem) => Align( // alignment: Alignment.centerLeft, // child: Text( // selectedItem ?? "Select", // style: TextStyle(fontSize: 12), // ), // ), // // // onChanged: (String? newValue) { // // setState(() { // // // selectedFrom[index] = countryMap.entries // // // .firstWhere((entry) => entry.value == newValue) // // // .key; // // // // selectedFrom = countryMap.entries // // .firstWhere((entry) => entry.value == newValue) // // .key; // // // // print(selectedFrom); // // }); // // }, // onChanged: (String? newValue) { // setState(() { // selectedFrom = // countryMap.entries // .firstWhere( // (entry) => entry.value == newValue, // ) // .key; // }); // }, // ), // ), // // child: SizedBox( // // height: 40, // // child: TextField( // // focusNode: _fromFocusNode, // // controller: _fromController, // // 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), // // ), // // ), // // ), // ), CustomTextFieldItnerarySubWrapper( isFocused: _fromFocus ?? false, padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, child: SizedBox( height: 40, child: Focus( focusNode: _fromFocusNode, onFocusChange: (hasFocus) { setState(() { _fromFocus = hasFocus; }); }, child: GestureDetector( onTap: () { _fromFocusNode?.requestFocus(); }, child: DropdownSearch( selectedItem: countryMap[selectedFrom], popupProps: PopupProps.menu( showSearchBox: true, fit: FlexFit.loose, constraints: BoxConstraints(maxHeight: 150),// maxHeight: 250 menuProps: const MenuProps(backgroundColor: Colors.white), itemBuilder: (context, item, isSelected) => Container( color: Colors.white, padding: EdgeInsets.symmetric( horizontal: 10, vertical: 6, ), child: Text( item, style: GoogleFonts.poppins(fontSize: 11.5), ), ), searchFieldProps: TextFieldProps( decoration: InputDecoration( hintText: "Search ...", contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), ), items: countryMap.values.toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( // border: InputBorder.none, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide( color: (_fromFocus ?? false) ? layoutColor! : Colors.white, width: 1, ), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: (_fromFocus ?? false) ? layoutColor : Colors.white, // : const Color(0xFFD6D5E6), width: 1, // const Color(0xFFD6D5E6), ), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: layoutColor, width: 1), ), contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), dropdownBuilder: (context, selectedItem) => Align( alignment: Alignment.centerLeft, child: Text( selectedItem ?? "Select ", style: GoogleFonts.poppins( fontSize: 12, color: Colors.black, ), ), ), onChanged: (String? newValue) { setState(() { selectedFrom = countryMap.entries .firstWhere((entry) => entry.value == newValue) .key; }); }, ),),) ), ), if (errorMessages["from_station"] != 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: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFF575A74), ), ), SizedBox(height: 5), // CustomTextFieldItnerarySubWrapper( // isFocused: _toFocus, // isDesktop: isDesktop, // child: SizedBox( // height: 40, // child: // isCountryLoading // ? Center(child: CircularProgressIndicator()) // : DropdownSearch( // selectedItem: // selectedTo != null // ? countryMap[selectedTo] // get the display value from code // : null, // popupProps: PopupProps.menu( // menuProps: MenuProps(backgroundColor: Colors.white), // constraints: BoxConstraints(maxHeight: 230), // showSearchBox: true, // searchFieldProps: TextFieldProps( // decoration: InputDecoration( // hintText: "Search ...", // contentPadding: EdgeInsets.symmetric( // horizontal: 10, // ), // ), // ), // ), // items: countryMap.values.toList(), // dropdownDecoratorProps: DropDownDecoratorProps( // dropdownSearchDecoration: InputDecoration( // border: InputBorder.none, // contentPadding: EdgeInsets.symmetric(horizontal: 1), // ), // ), // dropdownBuilder: // (context, selectedItem) => Align( // alignment: Alignment.centerLeft, // child: Text( // selectedItem ?? "Select", // style: TextStyle(fontSize: 12), // ), // ), // onChanged: (String? newValue) { // setState(() { // selectedTo = // countryMap.entries // .firstWhere( // (entry) => entry.value == newValue, // ) // .key; // }); // }, // ), // ), // ), CustomTextFieldItnerarySubWrapper( isFocused: _toFocus ?? false, isDesktop: isDesktop, padding: const EdgeInsets.symmetric(horizontal: 0), child: SizedBox( height: 40, child: Focus( focusNode: _toFocusNode, onFocusChange: (hasFocus) { setState(() { _toFocus = hasFocus; }); }, child: GestureDetector( onTap: () { _toFocusNode?.requestFocus(); }, child: DropdownSearch( selectedItem: countryMap[selectedTo], popupProps: PopupProps.menu( showSearchBox: true, fit: FlexFit.loose, constraints: BoxConstraints(maxHeight: 150), menuProps: const MenuProps(backgroundColor: Colors.white), itemBuilder: (context, item, isSelected) => Container( color: Colors.white, padding: EdgeInsets.symmetric( horizontal: 10, vertical: 6, ), child: Text( item, style: GoogleFonts.poppins(fontSize: 11.5), ), ), searchFieldProps: TextFieldProps( decoration: InputDecoration( hintText: "Search ...", contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), ), items: countryMap.values.toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( // border: InputBorder.none, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide( color: (_toFocus ?? false) ? layoutColor! : Colors.white, width: 1, ), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: (_toFocus ?? false) ? layoutColor : Colors.white, // : const Color(0xFFD6D5E6), width: 1, // const Color(0xFFD6D5E6), ), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: layoutColor, width: 1), ), contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), dropdownBuilder: (context, selectedItem) => Align( alignment: Alignment.centerLeft, child: Text( selectedItem ?? "Select ", style: GoogleFonts.poppins( fontSize: 12, color: Colors.black, ), ), ), onChanged: (String? newValue) { setState(() { selectedTo = countryMap.entries .firstWhere((entry) => entry.value == newValue) .key; }); }, ),),), ), ), if (errorMessages["to_station"] != null) ...[ SizedBox(height: 5), // Space before error message Text( errorMessages["to_station"]!, style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), if (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Date *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _dateFocus, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, child: SizedBox( height: 40, child: GestureDetector( // onTap: () => _selectCheckOutDate(context), onTap: () { _dateFocusNode.requestFocus(); _selectCheckOutDate(context); }, child: AbsorbPointer( child: TextField( focusNode: _dateFocusNode, controller: _dateController, readOnly: true, // Prevents typing 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"] != 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: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _timeFocus, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null, child: SizedBox( height: 40, child: GestureDetector( onTap: () { _timeController.text = ""; _timeFocusNode.requestFocus(); _selectCheckOutTime(context); }, child: AbsorbPointer( child: TextField( focusNode: _timeFocusNode, controller: _timeController, readOnly: true, 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"] != null) ...[ SizedBox(height: 5), // Space before error message Text( errorMessages["time"]!, style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), ]; } List _buildThirdRow(bool isDesktop) { return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Comments", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _commentsFocus, // Dropdown doesn't use focus isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null, child: SizedBox( height: 40, child: TextField( focusNode: _commentsFocusNode, controller: _trainCommentsController, // 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: 16), ), ), ), ), ], ), if (isDesktop) Spacer(), SizedBox(height: 5), Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.end, children: _handleAction(isDesktop), ), ], ), ]; } List _handleAction(bool isDesktop) { return [ // Close Button ElevatedButton( onPressed: () { // widget.onClose(false); widget.onClose("Train", false); }, 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), ), ), ]; } }