import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; class ForexScreen extends StatefulWidget { final Map formData; final Map? apiData; final Function(String tab, String key, String value) updateFormData; final Function(bool) onClose; ForexScreen({ required this.formData, required this.updateFormData, required this.onClose, this.apiData, }); @override _ForexScreenState createState() => _ForexScreenState(); } class _ForexScreenState extends State { final GlobalKey _formKey = GlobalKey(); Map selectedValues = {}; bool isChecked = false; // State variable for checkbox final FocusNode _tripTypeFocusNode = FocusNode(); final FocusNode _hotelNameFocusNode = FocusNode(); final FocusNode _fromFocusNode = FocusNode(); final FocusNode _toFocusNode = FocusNode(); final FocusNode _dateFocusNode = FocusNode(); final FocusNode _timeFocusNode = FocusNode(); final FocusNode _commentsFocusNode = FocusNode(); late Map _controllers; late TextEditingController _tripTypeController = TextEditingController(); late TextEditingController _hotelNameController = TextEditingController(); late TextEditingController _fromController = TextEditingController(); late TextEditingController _toController = TextEditingController(); late TextEditingController _dateController = TextEditingController(); late TextEditingController _endDateController = TextEditingController(); late TextEditingController _timeController = TextEditingController(); late TextEditingController _commentsController = TextEditingController(); bool _tripTypeFocused = false; bool _isHotelNameFocused = false; bool _fromFocus = false; bool _toFocus = false; bool _dateFocus = false; bool _timeFocus = false; bool _commentsFocus = false; @override void initState() { super.initState(); _tripTypeFocusNode.addListener(() { setState(() { _tripTypeFocused = _tripTypeFocusNode.hasFocus; }); _hotelNameFocusNode.addListener(() { setState(() { _isHotelNameFocused = _hotelNameFocusNode.hasFocus; }); }); _fromFocusNode.addListener(() { setState(() { _fromFocus = _fromFocusNode.hasFocus; }); }); _toFocusNode.addListener(() { setState(() { _toFocus = _toFocusNode.hasFocus; }); }); _dateFocusNode.addListener(() { setState(() { _dateFocus = _fromFocusNode.hasFocus; }); }); _timeFocusNode.addListener(() { setState(() { _timeFocus = _timeFocusNode.hasFocus; }); }); _commentsFocusNode.addListener(() { setState(() { _commentsFocus = _commentsFocusNode.hasFocus; }); }); }); _tripTypeController = TextEditingController( text: widget.formData["tripType"] ?? "", ); _hotelNameController = TextEditingController( text: widget.formData["_hotelName"] ?? "", ); _fromController = TextEditingController( text: widget.formData["_from"] ?? "", ); _toController = TextEditingController( text: widget.formData["_Check_In_Time"] ?? "", ); _dateController = TextEditingController( text: widget.formData["_Check_Out"] ?? "", ); _endDateController = TextEditingController( text: widget.formData["_Check_In"] ?? "", ); _timeController = TextEditingController( text: widget.formData["_Check_Out_Time"] ?? "", ); _commentsController = TextEditingController( text: widget.formData["_comments"] ?? "", ); // Save data when user types _tripTypeController.addListener(() { widget.updateFormData("Bus", "_tripType", _tripTypeController.text); }); // Save data when user types _hotelNameController.addListener(() { widget.updateFormData("Bus", "_hotelName", _hotelNameController.text); }); _fromController.addListener(() { widget.updateFormData("Bus", "_from", _fromController.text); }); _toController.addListener(() { widget.updateFormData("Bus", "_Check_In_Time", _toController.text); }); _dateController.addListener(() { widget.updateFormData("Bus", "_Check_Out", _dateController.text); }); _endDateController.addListener(() { widget.updateFormData("Bus", "_Check_In", _endDateController.text); }); _timeController.addListener(() { widget.updateFormData("Bus", "_Check_Out_Time", _timeController.text); }); _commentsController.addListener(() { widget.updateFormData("Bus", "_comments", _commentsController.text); }); } @override void dispose() { _tripTypeFocusNode.dispose(); _tripTypeController.dispose(); _hotelNameController.dispose(); _fromController.dispose(); _toController.dispose(); _dateController.dispose(); _endDateController.dispose(); _timeController.dispose(); _commentsController.dispose(); super.dispose(); } @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( "Forex List", 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)), ), ), ], ), ), ), ); }, ); } 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(_buildCardDetailsRow(isDesktop)), ...buildResponsiveRow(_buildFprexCard(isDesktop)), ...buildResponsiveRow(_buildThirdRow(isDesktop)), // Actions row remains a Row Row( mainAxisAlignment: MainAxisAlignment.end, children: _handleAction(isDesktop), ), ]; } List _buildFirstRow(isDesktop) { DateTime? _selectedCheckOutDate; DateTime? _selectedEndDate; 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); }); } } ; Future _selectForexEndDate(BuildContext context) async { DateTime now = DateTime.now(); DateTime today = DateTime(now.year, now.month, now.day); DateTime? pickedDate = await showDatePicker( context: context, initialDate: _selectedEndDate != null && _selectedEndDate!.isAfter(today) ? _selectedEndDate! : today, firstDate: today, lastDate: DateTime(2100), ); if (pickedDate != null && pickedDate != _selectedEndDate) { setState(() { _selectedEndDate = pickedDate; _endDateController.text = DateFormat('yyyy-MM-dd').format(pickedDate); }); } } return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Forex Start Date", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: _dateFocus, isDesktop: isDesktop, child: SizedBox( height: 40, child: GestureDetector( onTap: () => _selectCheckOutDate(context), child: AbsorbPointer( child: TextField( focusNode: _dateFocusNode, controller: _dateController, 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 (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Forex End Date", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: _dateFocus, isDesktop: isDesktop, child: SizedBox( height: 40, child: GestureDetector( onTap: () => _selectForexEndDate(context), child: AbsorbPointer( child: TextField( focusNode: _dateFocusNode, controller: _endDateController, 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, ), ), ), ), ), ), ), ], ), ]; } 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 [ CustomTextFieldWrapper( isFocused: _isHotelNameFocused, isDesktop: isDesktop, child: SizedBox( height: 40, child: DropdownButtonFormField( focusNode: _tripTypeFocusNode, // Assign the correct focus node value: selectedPurpose, style: TextStyle(fontSize: 12), decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.symmetric( horizontal: 10, ), // Proper padding ), onChanged: purposeList.isNotEmpty ? (newValue) { setState(() { selectedPurpose = newValue; }); print( "Updating form data: Flight -> trip_type -> ${newValue ?? ""}", ); widget.updateFormData( "Flight", "trip_type", newValue ?? "", ); } : null, items: dropdownItems, ), ), ), ]; } List _builClassType(bool isDesktop) { List purposeList = widget.apiData?['flight_class'] ?? []; 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 [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Class *", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: _isHotelNameFocused, isDesktop: isDesktop, child: SizedBox( height: 40, child: DropdownButtonFormField( focusNode: _hotelNameFocusNode, // Assign the correct focus node // controller: _hotelNameController, value: selectedPurpose, style: TextStyle(fontSize: 12), decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.symmetric( horizontal: 10, ), // Proper padding ), onChanged: purposeList.isNotEmpty ? (newValue) { setState(() { selectedPurpose = newValue; }); } : null, items: dropdownItems, ), // child: TextField( // focusNode: _hotelNameFocusNode, // Assign the correct focus node // controller: _hotelNameController, // style: TextStyle(fontSize: 12), // decoration: InputDecoration( // labelText: "Select Class", // labelStyle: TextStyle(fontSize: 12, color: Colors.grey), // floatingLabelBehavior: FloatingLabelBehavior.never, // border: InputBorder.none, // contentPadding: EdgeInsets.symmetric(vertical: 16), // ), // ), ), ), ], ), ]; } List _buildSecondRow(bool isDesktop) { return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Transport", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _fromFocus, isDesktop: isDesktop, child: SizedBox( height: 40, child: TextField( inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')), ], 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), ), ), ), ), ], ), if (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Accomodation", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _toFocus, isDesktop: isDesktop, child: SizedBox( height: 40, child: TextField( focusNode: _toFocusNode, controller: _toController, 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 (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Telephone", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _fromFocus, isDesktop: isDesktop, 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), ), ), ), ), ], ), if (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Other Expenses", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _toFocus, isDesktop: isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: Padding( padding: const EdgeInsets.all(8.0), child: Text( "Rs ", // focusNode: _toFocusNode, // controller: _toController, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), // decoration: const InputDecoration( // labelText: "To", // labelStyle: TextStyle(fontSize: 12, color: Colors.grey), // floatingLabelBehavior: FloatingLabelBehavior.never, // border: InputBorder.none, // contentPadding: EdgeInsets.symmetric(vertical: 16), // ), ), ), ), ), ], ), ]; } List _buildCardDetailsRow(bool isDesktop) { List purposeList = widget.apiData?['flight_class'] ?? []; 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 [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Card Number*", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _fromFocus, isDesktop: isDesktop, 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), ), ), ), ), ], ), if (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Currency*", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _toFocus, isDesktop: isDesktop, child: SizedBox( height: 40, child: DropdownButtonFormField( focusNode: _hotelNameFocusNode, // Assign the correct focus node // controller: _hotelNameController, value: selectedPurpose, style: TextStyle(fontSize: 12), decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.symmetric( horizontal: 10, ), // Proper padding ), onChanged: purposeList.isNotEmpty ? (newValue) { setState(() { selectedPurpose = newValue; }); } : null, items: dropdownItems, ), ), ), ], ), if (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Card*", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _toFocus, isDesktop: isDesktop, child: SizedBox( height: 40, child: TextField( focusNode: _toFocusNode, controller: _toController, 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 (isDesktop) Spacer() else SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Cash*", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: _fromFocus, isDesktop: isDesktop, 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), ), ), ), ), ], ), ]; } List _buildThirdRow(bool isDesktop) { return [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Delivery Location", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: _commentsFocus, // Dropdown doesn't use focus isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.4 : MediaQuery.of(context).size.width * 0.66, child: TextField( focusNode: _commentsFocusNode, controller: _commentsController, maxLines: 3, 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 _buildFprexCard(bool isDesktop) { return [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Checkbox( value: isChecked, side: BorderSide( color: Colors.grey, // Change border color width: 1, // Adjust thickness ), onChanged: (bool? value) { setState(() { isChecked = value!; }); }, ), Text( "Check If You Don't Have a forex Account", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), ], ), ]; } List _handleAction(bool isDesktop) { return [ // Close Button ElevatedButton( onPressed: () { Navigator.of(context).pop(); // 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: () { // TODO: Implement save logic }, 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), ), ), ]; } }