From 7f897a7296e2f918d5b036ba508d9bf0fda28424 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Thu, 19 Jun 2025 17:19:54 +0530 Subject: [PATCH 1/2] trip highlighter --- .../authentication/login/login_widget.dart | 5 +- lib/Screens/itnerary/flights.dart | 435 ++++--- lib/Screens/organization/mailSettings.dart | 260 ++-- lib/Screens/plans/create_plans.dart | 1148 ++++++++++------- lib/widgets/custom_text_field.dart | 43 +- lib/widgets/custom_text_itnerary_sub.dart | 66 +- 6 files changed, 1134 insertions(+), 823 deletions(-) diff --git a/lib/Screens/authentication/login/login_widget.dart b/lib/Screens/authentication/login/login_widget.dart index e67651c..783cbc8 100644 --- a/lib/Screens/authentication/login/login_widget.dart +++ b/lib/Screens/authentication/login/login_widget.dart @@ -415,8 +415,9 @@ class _LoginWidgetState extends State { // fit: BoxFit.contain, // ), Container( - width: 200, // Optional: control size - height: 100, + // color: Colors.yellow, + width: 120, // Optional: control size + height: 200, ), Expanded( child: Container( diff --git a/lib/Screens/itnerary/flights.dart b/lib/Screens/itnerary/flights.dart index 18212dc..12ec138 100644 --- a/lib/Screens/itnerary/flights.dart +++ b/lib/Screens/itnerary/flights.dart @@ -988,64 +988,80 @@ class FlightScreenState extends State { child: SizedBox( height: 40, width: double.infinity, - child: DropdownSearch( - items: - purposeList - .map((item) => item['dropdown_value'] as String) - .toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), - ), - ), - onChanged: (newValue) { + child: Focus( + focusNode: focusNodes["_tripType1FocusNode"], + onFocusChange: (hasFocus) { 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; - } + focusStates["_tripType1Focused"] = hasFocus; }); - 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), + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_tripType1FocusNode"]?.requestFocus(); + }, + child: DropdownSearch( + items: + purposeList + .map((item) => item['dropdown_value'] as String) + .toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(horizontal: 1), ), ), - 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, + 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), + ), ), - child: Text( - item, - style: TextStyle( - fontSize: 13, - ), // Custom text size for dropdown items - ), - ), + 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 + ), + ), + ), + ), ), ), @@ -1419,156 +1435,180 @@ class FlightScreenState extends State { child: isCountryLoading ? Center(child: CircularProgressIndicator()) - : DropdownSearch( - enabled: - !(selectedTripType == "Roundtrip" && index == 2), - selectedItem: - selectedFrom[index] != null - ? countryMap[selectedFrom[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, + : 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( + enabled: + !(selectedTripType == "Roundtrip" && + index == 2), + selectedItem: + selectedFrom[index] != null + ? countryMap[selectedFrom[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), ), - ), - 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, + menuProps: MenuProps( + backgroundColor: Colors.white, ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, + 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: [ - Text( - city, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), + 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( - code, + airport, style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, + fontSize: 11, + color: Colors.grey, + overflow: TextOverflow.ellipsis, ), ), ], ), - 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: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + // 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: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 1, + ), + ), + ), + 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]!; + } + }); + }, ), ), - 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]!; - } - }); - }, ), ), @@ -1941,6 +1981,7 @@ class FlightScreenState extends State { SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( isFocused: focusStates["_date${index}Focused"] ?? false, + isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, child: SizedBox( @@ -1994,7 +2035,7 @@ class FlightScreenState extends State { ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_timeFocused"] ?? false, + isFocused: focusStates["_time${index}Focused"] ?? false, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null, child: SizedBox( @@ -2013,6 +2054,7 @@ class FlightScreenState extends State { ); // ✅ Force rebuild to show the error immediately }); }, + child: AbsorbPointer( child: TextField( focusNode: focusNodes["_time${index}FocusNode"], @@ -2034,6 +2076,19 @@ class FlightScreenState extends State { ), ), ), + // 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(); + // }, ), ), ), diff --git a/lib/Screens/organization/mailSettings.dart b/lib/Screens/organization/mailSettings.dart index f8af175..b75af06 100644 --- a/lib/Screens/organization/mailSettings.dart +++ b/lib/Screens/organization/mailSettings.dart @@ -34,10 +34,10 @@ class _MailSettingState extends State { List dataHeader = [ "host", "userName", - "password", + "mail_password", "port", "senderEmail", - "toEmail" + "toEmail", ]; Map getMailData() => mailData; @@ -46,7 +46,7 @@ class _MailSettingState extends State { final data = { "mail_host": controllers["host"]?.text, "mail_user_name": controllers["userName"]?.text, - "mail_password": controllers["password"]?.text, + "mail_password": controllers["mail_password"]?.text, "mail_port": controllers["port"]?.text, "sender_email": controllers["senderEmail"]?.text, "to_mail": controllers["toEmail"]?.text, @@ -97,7 +97,7 @@ class _MailSettingState extends State { widget.initialMailData['sender_email'] ?? ''; controllers["userName"]?.text = widget.initialMailData['mail_user_name'] ?? ''; - controllers["password"]?.text = + controllers["mail_password"]?.text = widget.initialMailData['mail_password'] ?? ''; controllers["host"]?.text = widget.initialMailData['mail_host'] ?? ''; controllers["port"]?.text = @@ -181,8 +181,9 @@ class _MailSettingState extends State { // Email validation if (data["to_mail"] != null && data["to_mail"].toString().isNotEmpty) { - if (!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$") - .hasMatch(data["to_mail"].toString())) { + if (!RegExp( + r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", + ).hasMatch(data["to_mail"].toString())) { errorMessages["to_mail"] = "Invalid email format"; // Invalid email format } @@ -191,8 +192,9 @@ class _MailSettingState extends State { // Email validation if (data["sender_email"] != null && data["sender_email"].toString().isNotEmpty) { - if (!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$") - .hasMatch(data["sender_email"].toString())) { + if (!RegExp( + r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", + ).hasMatch(data["sender_email"].toString())) { errorMessages["sender_email"] = "Invalid email format"; // Invalid email format } @@ -226,17 +228,19 @@ class _MailSettingState extends State { Text( "Sender Email", style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: widget.isDesktop, - width: widget.isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + widget.isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( @@ -249,8 +253,8 @@ class _MailSettingState extends State { if (value.trim().isEmpty) { errorMessages["sender_email"] = "Required"; } else if (!RegExp( - r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$") - .hasMatch(value)) { + r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", + ).hasMatch(value)) { errorMessages["sender_email"] = "Invalid email format"; } @@ -259,7 +263,9 @@ class _MailSettingState extends State { decoration: InputDecoration( labelText: "sender email", labelStyle: GoogleFonts.poppins( - fontSize: 12, color: Colors.grey), + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -278,36 +284,28 @@ class _MailSettingState extends State { ), ], ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), widget.isDesktop ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: _buildMailFirstRow(widget.isDesktop), - ) + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _buildMailFirstRow(widget.isDesktop), + ) : Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: _buildMailFirstRow(widget.isDesktop), - ), + crossAxisAlignment: CrossAxisAlignment.center, + children: _buildMailFirstRow(widget.isDesktop), + ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), widget.isDesktop ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: _buildMailSecondRow(widget.isDesktop), - ) - : Column( - children: _buildMailSecondRow(widget.isDesktop), - ), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _buildMailSecondRow(widget.isDesktop), + ) + : Column(children: _buildMailSecondRow(widget.isDesktop)), - SizedBox( - height: 10, - ), + SizedBox(height: 10), Container( // color: Color(0xFFF7F7FB), @@ -317,7 +315,9 @@ class _MailSettingState extends State { Text( "Test Mail", style: GoogleFonts.poppins( - color: Color(0xFF114D8B), fontWeight: FontWeight.w600), + color: Color(0xFF114D8B), + fontWeight: FontWeight.w600, + ), ), ], ), @@ -327,7 +327,7 @@ class _MailSettingState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: _buildTestMail(widget.isDesktop), - ) + ), ], ), ), @@ -342,17 +342,19 @@ class _MailSettingState extends State { Text( "User Name", style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: widget.isDesktop, - width: widget.isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + widget.isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( @@ -364,8 +366,10 @@ class _MailSettingState extends State { style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "user name", - labelStyle: - GoogleFonts.poppins(fontSize: 12, color: Colors.grey), + labelStyle: GoogleFonts.poppins( + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -388,47 +392,56 @@ class _MailSettingState extends State { Text( "Password", style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: widget.isDesktop, - width: widget.isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + widget.isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( // focusNode: _destinationFocusNode, - controller: controllers["password"], + controller: controllers["mail_password"], onChanged: (value) { _clearError("mail_password"); }, - obscureText: _obscurePassword, + // obscureText: _obscurePassword, + autofillHints: const [ + // AutofillHints.newPassword, + ], // <--- This is key + enableSuggestions: false, // <--- Disable suggestions + autocorrect: false, style: TextStyle(fontSize: 12), decoration: InputDecoration( - labelText: "password", - labelStyle: - GoogleFonts.poppins(fontSize: 12, color: Colors.grey), + labelText: "Access Key", + labelStyle: GoogleFonts.poppins( + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), - suffixIcon: IconButton( - icon: Icon( - _obscurePassword - ? Icons.visibility_off - : Icons.visibility, - size: 16, - ), - onPressed: () { - setState(() { - _obscurePassword = !_obscurePassword; - }); - }, - ), + // suffixIcon: IconButton( + // icon: Icon( + // _obscurePassword + // ? Icons.visibility_off + // : Icons.visibility, + // size: 16, + // ), + // onPressed: () { + // setState(() { + // _obscurePassword = !_obscurePassword; + // }); + // }, + // ), ), ), ), @@ -453,17 +466,19 @@ class _MailSettingState extends State { Text( "Host", style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: widget.isDesktop, - width: widget.isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + widget.isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( @@ -475,8 +490,10 @@ class _MailSettingState extends State { style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "host", - labelStyle: - GoogleFonts.poppins(fontSize: 12, color: Colors.grey), + labelStyle: GoogleFonts.poppins( + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -499,17 +516,19 @@ class _MailSettingState extends State { Text( "Port", style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: widget.isDesktop, - width: widget.isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + widget.isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( @@ -521,8 +540,10 @@ class _MailSettingState extends State { style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "port", - labelStyle: - GoogleFonts.poppins(fontSize: 12, color: Colors.grey), + labelStyle: GoogleFonts.poppins( + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -550,17 +571,19 @@ class _MailSettingState extends State { Text( "Enter Your Mail Id", style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: widget.isDesktop, - width: widget.isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + widget.isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( @@ -573,16 +596,18 @@ class _MailSettingState extends State { if (value.trim().isEmpty) { errorMessages["to_mail"] = "Required"; } else if (!RegExp( - r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$") - .hasMatch(value)) { + r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", + ).hasMatch(value)) { errorMessages["to_mail"] = "Invalid email format"; } }, style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "To mail", - labelStyle: - GoogleFonts.poppins(fontSize: 12, color: Colors.grey), + labelStyle: GoogleFonts.poppins( + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -599,31 +624,28 @@ class _MailSettingState extends State { ], ], ), - SizedBox( - width: 10, - ), + SizedBox(width: 10), Column( children: [ ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF114D8B), // Keep original color - foregroundColor: Colors.white, // Keep original color - disabledBackgroundColor: - Color(0xFF114D8B), // Ensure color remains when disabled - disabledForegroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: Color(0xFF114D8B), width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12), + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF114D8B), // Keep original color + foregroundColor: Colors.white, // Keep original color + disabledBackgroundColor: Color( + 0xFF114D8B, + ), // Ensure color remains when disabled + disabledForegroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Color(0xFF114D8B), width: 2), ), - onPressed: () { - handleTestMailSubmit(); - }, - child: Text( - "Test Email", - style: GoogleFonts.poppins(fontSize: 12), - )) + padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12), + ), + onPressed: () { + handleTestMailSubmit(); + }, + child: Text("Test Email", style: GoogleFonts.poppins(fontSize: 12)), + ), ], ), ]; diff --git a/lib/Screens/plans/create_plans.dart b/lib/Screens/plans/create_plans.dart index ea3b6ca..5e23763 100644 --- a/lib/Screens/plans/create_plans.dart +++ b/lib/Screens/plans/create_plans.dart @@ -383,11 +383,11 @@ class CreateNewPlansState extends State { final TextEditingController _descriptionController = TextEditingController(); final TextEditingController _remarksController = TextEditingController(); - final FocusNode _tripTitleFocusNode = FocusNode(); - final FocusNode _descriptionFocusNode = FocusNode(); // Declare FocusNode + // final FocusNode _tripTitleFocusNode = FocusNode(); + // final FocusNode _descriptionFocusNode = FocusNode(); // Declare FocusNode - bool _isdescriptionFocused = false; - bool _isTripTitleFocused = false; + // bool _isdescriptionFocused = false; + // bool _isTripTitleFocused = false; late String _selectedOption = "Option 1"; // late String? _selectedIsBillable = "Billable"; @@ -450,6 +450,9 @@ class CreateNewPlansState extends State { List> planStatusList = []; + Map focusNodes = {}; + Map focusStates = {}; + late bool isApproverApproved = false; late bool isApproverRejected = false; @@ -483,6 +486,16 @@ class CreateNewPlansState extends State { // "status_value": statusValue, }; + List dataHeader = [ + "trip_planned", + "trip_type", + "cost_center_id", + "is_billable", + "purpose_of_travel", + "description", + "functional_department", + ]; + void handleItineraryUpdate(String type, List> newList) { setState(() { switch (type) { @@ -530,34 +543,62 @@ class CreateNewPlansState extends State { } flightTripTypeNotifier = ValueNotifier(null); + for (var field in dataHeader) { + focusNodes["${field}FocusNode"] = FocusNode(); + focusStates["${field}Focused"] = false; + } + + print("Focus Nodes KeysII: ${focusNodes.keys.toList()}"); + print("Focus States KeysII: ${focusStates.keys.toList()}"); + + for (var key in focusNodes.keys) { + _addFocusListener(focusNodes[key]!, (focus) { + setState(() { + focusStates[key.replaceFirst("FocusNode", "Focused")] = focus; + }); + }); + } + fetchUserDetails(); fetchPlans(); fetchCostCenter(); fetchCountryList(); - _tripTitleFocusNode.addListener(() { - setState(() { - _isTripTitleFocused = _tripTitleFocusNode.hasFocus; - }); - }); - - _descriptionFocusNode.addListener(() { - setState(() { - _isdescriptionFocused = _descriptionFocusNode.hasFocus; - }); - }); + // _tripTitleFocusNode.addListener(() { + // setState(() { + // _isTripTitleFocused = _tripTitleFocusNode.hasFocus; + // }); + // }); + // + // _descriptionFocusNode.addListener(() { + // setState(() { + // _isdescriptionFocused = _descriptionFocusNode.hasFocus; + // }); + // }); handleUpdateData(); } @override void dispose() { - _tripTitleFocusNode.dispose(); - _descriptionFocusNode.dispose(); + for (var node in focusNodes.values) { + node.dispose(); + } + + // _tripTitleFocusNode.dispose(); + // _descriptionFocusNode.dispose(); super.dispose(); } + void _addFocusListener(FocusNode node, Function(bool) updateState) { + node.addListener(() { + setState(() { + updateState(node.hasFocus); + }); + }); + } + void handleSelectedUser() { if (widget.selectedPlanData != null) { setState(() { @@ -1236,7 +1277,29 @@ class CreateNewPlansState extends State { // await postPlanData(planData); print("Hide loader at: ${DateTime.now()}"); // Close loading dialog (ONLY if still mounted) - if (mounted) Navigator.of(context, rootNavigator: true).pop(); + Future.delayed(Duration(seconds: 12), () { + if (mounted) { + Navigator.of(context, rootNavigator: true).pop(); + + final currentUri = + GoRouterState.of( + context, + ).uri.toString(); // ✅ safer than `.location` + print("currentUri - $currentUri"); + + if (currentUri == "/allTrips/trips") { + context.go('/listAllPlan'); + } else if (currentUri == "/createPlan") { + context.go('/listPlan'); + } else { + widget.isApprover + ? context.go('/approvallist') + : context.go('/listPlan'); + } + } + }); + + // if (mounted) Navigator.of(context, rootNavigator: true).pop(); } }); } @@ -1741,95 +1804,110 @@ class CreateNewPlansState extends State { SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: false, + isFocused: focusStates["trip_typeFocused"] ?? false, isDesktop: widget.isDesktop, child: SizedBox( height: 35, width: double.infinity, - child: DropdownSearch>( - popupProps: PopupProps.menu( - showSearchBox: false, // Optionally enable search - 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, // 👈 Smaller font size - color: Colors.black, + child: Focus( + focusNode: focusNodes["trip_typeFocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["trip_typeFocused"] = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + focusNodes["trip_typeFocusNode"]?.requestFocus(); + }, + child: DropdownSearch>( + popupProps: PopupProps.menu( + showSearchBox: false, // Optionally enable search + 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, // 👈 Smaller font size + color: Colors.black, + ), + ), + ); + }, + ), + dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, // No underline + + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, ), ), - ); - }, - ), - dropdownDecoratorProps: const DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, // No underline - - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, ), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || selectedItem.isEmpty) { + return Text( + "Select Trip Type", + style: GoogleFonts.poppins( + color: Colors.grey, + fontSize: 13, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ); + }, + selectedItem: tripTypeList.firstWhere( + (item) => item['dropdown_key'] == _selectedTripType, + orElse: () => {}, + ), + itemAsString: (item) => item['dropdown_value'] ?? '', + items: getFilteredTripTypes(), + + // items: + // [ + // {"dropdown_key": "1", "dropdown_value": "Domestic"}, + // {"dropdown_key": "2", "dropdown_value": "International"}, + // ].map>((item) { + // return Map.from(item); + // }).toList(), + onChanged: + widget.isViewMode + ? null + : (Map? newItem) { + if (newItem != null) { + setState(() { + _selectedTripType = + newItem['dropdown_key'].toString(); + // Notify FlightScreen + flightTripTypeNotifier.value = + _selectedTripType; + print( + "flightTripTypeNotifier- ${flightTripTypeNotifier.value}", + ); + fetchTrainFlightClass( + int.parse(_selectedTripType!), + ); + dynamicItineraryKey.currentState + ?.updateSelectedServices(); + }); + } + }, ), ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Trip Type", - style: GoogleFonts.poppins( - color: Colors.grey, - fontSize: 13, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ); - }, - selectedItem: tripTypeList.firstWhere( - (item) => item['dropdown_key'] == _selectedTripType, - orElse: () => {}, - ), - itemAsString: (item) => item['dropdown_value'] ?? '', - items: getFilteredTripTypes(), - - // items: - // [ - // {"dropdown_key": "1", "dropdown_value": "Domestic"}, - // {"dropdown_key": "2", "dropdown_value": "International"}, - // ].map>((item) { - // return Map.from(item); - // }).toList(), - onChanged: - widget.isViewMode - ? null - : (Map? newItem) { - if (newItem != null) { - setState(() { - _selectedTripType = - newItem['dropdown_key'].toString(); - // Notify FlightScreen - flightTripTypeNotifier.value = _selectedTripType; - print( - "flightTripTypeNotifier- ${flightTripTypeNotifier.value}", - ); - fetchTrainFlightClass( - int.parse(_selectedTripType!), - ); - dynamicItineraryKey.currentState - ?.updateSelectedServices(); - }); - } - }, ), ), ), @@ -1873,92 +1951,107 @@ class CreateNewPlansState extends State { SizedBox(height: 5), CustomTextFieldWrapper( + isFocused: focusStates["is_billableFocused"] ?? false, width: widget.isDesktop ? MediaQuery.of(context).size.width * 0.2 : null, - isFocused: false, + isDesktop: widget.isDesktop, child: SizedBox( height: 35, width: double.infinity, - child: DropdownSearch>( - 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: Focus( + focusNode: focusNodes["is_billableFocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["is_billableFocused"] = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + focusNodes["is_billableFocusNode"]?.requestFocus(); + }, + child: DropdownSearch>( + 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: const DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), ), - child: Text( - item['dropdown_value'] ?? '', + ), + selectedItem: purposeList + .cast>() + .firstWhere( + (item) => item['dropdown_key'] == _selectedIsBillable, + orElse: () => {}, + ), + dropdownButtonProps: const DropdownButtonProps( + icon: Icon(Icons.arrow_drop_down), + ), + // itemAsString: (item) => item['dropdown_value'] ?? '', + // items: purposeList.cast>(), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || selectedItem.isEmpty) { + return Text( + "Select Billable", // fallback text + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.grey, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', style: GoogleFonts.poppins( fontSize: 12, color: Colors.black, ), - ), - ); - }, - ), - dropdownDecoratorProps: const DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), + ); + }, + + items: + purposeList.map>((item) { + return Map.from( + item, + ); // Ensuring each item is properly cast + }).toList(), + onChanged: + widget.isViewMode + ? null + : (Map? newItem) { + if (newItem != null) { + setState(() { + _selectedIsBillable = + newItem['dropdown_key'].toString(); + }); + } + }, ), ), - selectedItem: purposeList - .cast>() - .firstWhere( - (item) => item['dropdown_key'] == _selectedIsBillable, - orElse: () => {}, - ), - dropdownButtonProps: const DropdownButtonProps( - icon: Icon(Icons.arrow_drop_down), - ), - // itemAsString: (item) => item['dropdown_value'] ?? '', - // items: purposeList.cast>(), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Billable", // fallback text - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.grey, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ); - }, - - items: - purposeList.map>((item) { - return Map.from( - item, - ); // Ensuring each item is properly cast - }).toList(), - onChanged: - widget.isViewMode - ? null - : (Map? newItem) { - if (newItem != null) { - setState(() { - _selectedIsBillable = - newItem['dropdown_key'].toString(); - }); - } - }, ), ), ), @@ -2132,7 +2225,9 @@ class CreateNewPlansState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: false, // Dropdown doesn't use focus + isFocused: + focusStates["cost_center_idFocused"] ?? + false, // Dropdown doesn't use focus isDesktop: widget.isDesktop, child: SizedBox( height: 35, @@ -2145,90 +2240,108 @@ class CreateNewPlansState extends State { child: CircularProgressIndicator(), ), ) - : DropdownSearch( - selectedItem: costCenterMap[selectedCostCenterId], - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Cost Center...", - // hintStyle: TextStyle(fontSize: 13, color: Colors.grey), - hintStyle: GoogleFonts.poppins( - fontSize: 13, - color: Colors.grey, - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - ), - ), - style: GoogleFonts.poppins(fontSize: 13), - ), - menuProps: MenuProps(backgroundColor: Colors.white), - itemBuilder: - (context, item, isSelected) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, - ), - child: Text( - item, - style: GoogleFonts.poppins( - fontSize: 13, - ), // 👈 Set your desired text size here - ), - ), - ), - - items: costCenterMap.values.toList(), // just names - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric(horizontal: 1), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - ), - ), - - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Purpose", // fallback text - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.grey, - ), - ); - } - return Text( - selectedItem ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ); - }, - // dropdownBuilder: (context, selectedItem) => Align( - // alignment: Alignment.centerLeft, - // child: Text( - // selectedItem ?? "Select", - // style: TextStyle(fontSize: 12), - // ), - // ), - onChanged: (String? newValue) { + : Focus( + focusNode: focusNodes["cost_center_idFocusNode"], + onFocusChange: (hasFocus) { setState(() { - selectedCostCenterId = - costCenterMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; + focusStates["cost_center_idFocused"] = hasFocus; }); }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + focusNodes["cost_center_idFocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch( + selectedItem: costCenterMap[selectedCostCenterId], + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Cost Center...", + // hintStyle: TextStyle(fontSize: 13, color: Colors.grey), + hintStyle: GoogleFonts.poppins( + fontSize: 13, + color: Colors.grey, + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + ), + ), + style: GoogleFonts.poppins(fontSize: 13), + ), + menuProps: MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Text( + item, + style: GoogleFonts.poppins( + fontSize: 13, + ), // 👈 Set your desired text size here + ), + ), + ), + + items: costCenterMap.values.toList(), // just names + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(horizontal: 1), + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || + selectedItem.isEmpty) { + return Text( + "Select Purpose", // fallback text + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.grey, + ), + ); + } + return Text( + selectedItem ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ); + }, + // dropdownBuilder: (context, selectedItem) => Align( + // alignment: Alignment.centerLeft, + // child: Text( + // selectedItem ?? "Select", + // style: TextStyle(fontSize: 12), + // ), + // ), + onChanged: (String? newValue) { + setState(() { + selectedCostCenterId = + costCenterMap.entries + .firstWhere( + (entry) => entry.value == newValue, + ) + .key; + }); + }, + ), + ), ), ), @@ -2286,8 +2399,9 @@ class CreateNewPlansState extends State { width: isDesktop ? MediaQuery.of(context).size.width * 0.2 - : MediaQuery.of(context).size.width * 0.85, - isFocused: false, // Dropdown doesn't use focus + : MediaQuery.of(context).size.width * 0.88, + isFocused: focusStates["purpose_of_travelFocused"] ?? false, + isDesktop: widget.isDesktop, child: SizedBox( height: 35, // Set appropriate height @@ -2297,95 +2411,117 @@ class CreateNewPlansState extends State { ? Center( child: CircularProgressIndicator(), ) // Show loading inside dropdown - : DropdownSearch>( - selectedItem: purposeList.firstWhere( - (item) => - item['dropdown_key'].toString() == - selectedPurpose, - orElse: () => {}, // ✅ Safe fallback - ), - items: purposeList, - itemAsString: - (Map item) => - item['dropdown_value'], - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Purpose...", - hintStyle: GoogleFonts.poppins( - fontSize: 13, - color: Colors.grey, + : Focus( + focusNode: focusNodes["purpose_of_travelFocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["purpose_of_travelFocused"] = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + focusNodes["purpose_of_travelFocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch>( + selectedItem: purposeList.firstWhere( + (item) => + item['dropdown_key'].toString() == + selectedPurpose, + orElse: + () => {}, // ✅ Safe fallback + ), + items: purposeList, + itemAsString: + (Map item) => + item['dropdown_value'], + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Purpose...", + hintStyle: GoogleFonts.poppins( + fontSize: 13, + color: Colors.grey, + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + ), + ), + style: GoogleFonts.poppins(fontSize: 13), ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, + menuProps: MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Text( + item['dropdown_value'], + style: GoogleFonts.poppins( + fontSize: 13, + ), // 👈 Set your desired text size here + ), + ), + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + border: InputBorder.none, ), ), - style: GoogleFonts.poppins(fontSize: 13), - ), - menuProps: MenuProps(backgroundColor: Colors.white), - itemBuilder: - (context, item, isSelected) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, - ), - child: Text( - item['dropdown_value'], + onChanged: + widget.isViewMode + ? null + : (Map? newValue) { + setState(() { + selectedPurpose = + newValue?['dropdown_key'] + .toString(); + }); + print( + "selectedPurpose - $selectedPurpose", + ); + }, + + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || + selectedItem.isEmpty) { + return Text( + "Select Purpose", // fallback text style: GoogleFonts.poppins( fontSize: 13, - ), // 👈 Set your desired text size here + color: Colors.grey, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: + 12, // 👈 Small font size for selected item + color: Colors.black, ), - ), - ), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - border: InputBorder.none, + ); + }, + // dropdownBuilder: (context, selectedItem) => Align( + // alignment: Alignment.centerLeft, + // child: Text( + // selectedItem?['dropdown_value'] ?? '', + // style: TextStyle(fontSize: 12), + // ), + // ), ), ), - onChanged: - widget.isViewMode - ? null - : (Map? newValue) { - setState(() { - selectedPurpose = - newValue?['dropdown_key'].toString(); - }); - print("selectedPurpose - $selectedPurpose"); - }, - - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Purpose", // fallback text - style: GoogleFonts.poppins( - fontSize: 13, - color: Colors.grey, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: - 12, // 👈 Small font size for selected item - color: Colors.black, - ), - ); - }, - // dropdownBuilder: (context, selectedItem) => Align( - // alignment: Alignment.centerLeft, - // child: Text( - // selectedItem?['dropdown_value'] ?? '', - // style: TextStyle(fontSize: 12), - // ), - // ), ), ), ), @@ -2446,12 +2582,12 @@ class CreateNewPlansState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: false, // Dropdown doesn't use focus + isFocused: focusStates["functional_departmentFocused"] ?? false, isDesktop: widget.isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.2 - : MediaQuery.of(context).size.width * 0.85, + : MediaQuery.of(context).size.width * 0.88, // width: MediaQuery.of(context).size.width * 0.2, child: SizedBox( height: 35, // Set appropriate height @@ -2460,99 +2596,122 @@ class CreateNewPlansState extends State { ? Center( child: CircularProgressIndicator(), ) // Show loading inside dropdown - : DropdownSearch>( - selectedItem: funcDeptList.firstWhere( - (item) => - item['dropdown_key'].toString() == - selectedFuncDept, - orElse: () => {}, // ✅ Safe fallback - ), - items: funcDeptList, - itemAsString: - (Map item) => - item['dropdown_value'], - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search department...", - hintStyle: GoogleFonts.poppins( - fontSize: 13, - color: Colors.grey, - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - ), - ), - style: GoogleFonts.poppins( - fontSize: - 13, // 👈 Small font size for selected item - ), - ), - menuProps: MenuProps(backgroundColor: Colors.white), - itemBuilder: - (context, item, isSelected) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, - ), - child: Text( - item['dropdown_value'], - style: GoogleFonts.poppins( - fontSize: - 13, // 👈 Small font size for selected item - ), // 👈 Set your desired text size here - ), - ), - ), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - border: InputBorder.none, - ), - ), - onChanged: - widget.isViewMode - ? null - : (Map? newValue) { - setState(() { - selectedFuncDept = - newValue?['dropdown_key'].toString(); - }); - print("selectedFuncDept - $selectedFuncDept"); - }, - - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return const Text( - "Select Purpose", // fallback text - style: TextStyle( - fontSize: 12, - color: Colors.grey, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: - 12, // 👈 Small font size for selected item - color: Colors.black, - ), - ); + : Focus( + focusNode: focusNodes["functional_departmentFocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["functional_departmentFocused"] = + hasFocus; + }); }, - // dropdownBuilder: (context, selectedItem) => Align( - // alignment: Alignment.centerLeft, - // child: Text( - // selectedItem?['dropdown_value'] ?? '', - // style: TextStyle(fontSize: 12), - // ), - // ), + child: GestureDetector( + onTap: () { + // Request focus when user taps + focusNodes["functional_departmentFocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch>( + selectedItem: funcDeptList.firstWhere( + (item) => + item['dropdown_key'].toString() == + selectedFuncDept, + orElse: + () => {}, // ✅ Safe fallback + ), + items: funcDeptList, + itemAsString: + (Map item) => + item['dropdown_value'], + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search department...", + hintStyle: GoogleFonts.poppins( + fontSize: 13, + color: Colors.grey, + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + ), + ), + style: GoogleFonts.poppins( + fontSize: + 13, // 👈 Small font size for selected item + ), + ), + menuProps: MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Text( + item['dropdown_value'], + style: GoogleFonts.poppins( + fontSize: + 13, // 👈 Small font size for selected item + ), // 👈 Set your desired text size here + ), + ), + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + border: InputBorder.none, + ), + ), + onChanged: + widget.isViewMode + ? null + : (Map? newValue) { + setState(() { + selectedFuncDept = + newValue?['dropdown_key'] + .toString(); + }); + print( + "selectedFuncDept - $selectedFuncDept", + ); + }, + + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || + selectedItem.isEmpty) { + return const Text( + "Select Purpose", // fallback text + style: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: + 12, // 👈 Small font size for selected item + color: Colors.black, + ), + ); + }, + // dropdownBuilder: (context, selectedItem) => Align( + // alignment: Alignment.centerLeft, + // child: Text( + // selectedItem?['dropdown_value'] ?? '', + // style: TextStyle(fontSize: 12), + // ), + // ), + ), + ), ), ), ), @@ -2578,65 +2737,83 @@ class CreateNewPlansState extends State { return [ CustomTextFieldWrapper( - isFocused: false, + isFocused: focusStates["trip_plannedFocused"] ?? false, + isDesktop: isDesktop, layoutColor: widget.layoutColor, child: SizedBox( height: 35, width: double.infinity, - child: DropdownSearch( - selectedItem: - options.firstWhere( - (opt) => opt['value'] == _selectedOption, - )['title'], - enabled: !widget.isViewMode, - items: options.map((opt) => opt['title']!).toList(), - popupProps: PopupProps.menu( - showSearchBox: false, - menuProps: const MenuProps(backgroundColor: Colors.white), - constraints: BoxConstraints(maxHeight: 100), - itemBuilder: - (context, item, isSelected) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, - ), - child: Text(item, style: GoogleFonts.poppins(fontSize: 13)), - ), - ), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - ), - ), - dropdownBuilder: (context, selectedItem) { - return Text( - selectedItem ?? "Select Purpose", - style: GoogleFonts.poppins( - fontSize: 12, - color: selectedItem == null ? Colors.grey : Colors.black, - ), - ); - }, - onChanged: (String? newTitle) { - if (newTitle == null) return; - final selected = options.firstWhere( - (opt) => opt["title"] == newTitle, - ); + child: Focus( + focusNode: focusNodes["trip_plannedFocusNode"], + onFocusChange: (hasFocus) { setState(() { - _selectedOption = selected["value"]!; - if (_selectedOption == "Option 2" || - _selectedOption == "Option 3") { - _showInputDialog(selected["title"]!); - } else if (_selectedOption == "Option 1") { - otherUserName = userName; - } + focusStates["trip_plannedFocused"] = hasFocus; }); }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + focusNodes["trip_plannedFocusNode"]?.requestFocus(); + }, + child: DropdownSearch( + selectedItem: + options.firstWhere( + (opt) => opt['value'] == _selectedOption, + )['title'], + enabled: !widget.isViewMode, + items: options.map((opt) => opt['title']!).toList(), + popupProps: PopupProps.menu( + showSearchBox: false, + menuProps: const MenuProps(backgroundColor: Colors.white), + constraints: BoxConstraints(maxHeight: 100), + itemBuilder: + (context, item, isSelected) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 13), + ), + ), + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + dropdownBuilder: (context, selectedItem) { + return Text( + selectedItem ?? "Select Purpose", + style: GoogleFonts.poppins( + fontSize: 12, + color: selectedItem == null ? Colors.grey : Colors.black, + ), + ); + }, + onChanged: (String? newTitle) { + if (newTitle == null) return; + final selected = options.firstWhere( + (opt) => opt["title"] == newTitle, + ); + setState(() { + _selectedOption = selected["value"]!; + if (_selectedOption == "Option 2" || + _selectedOption == "Option 3") { + _showInputDialog(selected["title"]!); + } else if (_selectedOption == "Option 1") { + otherUserName = userName; + } + }); + }, + ), + ), ), ), ), @@ -2892,12 +3069,13 @@ class CreateNewPlansState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _isTripTitleFocused, + isFocused: false, + // isFocused: _isTripTitleFocused, isDesktop: widget.isDesktop, child: SizedBox( height: 35, child: TextField( - focusNode: _tripTitleFocusNode, + // focusNode: _tripTitleFocusNode, controller: _tripTitleController, style: TextStyle(fontSize: 12), enabled: !widget.isViewMode, @@ -2963,8 +3141,8 @@ class CreateNewPlansState extends State { // ), // ), CustomTextFieldWrapper( - // isFocused: false, - isFocused: _isdescriptionFocused, + isFocused: focusStates["descriptionFocused"] ?? false, + // isFocused: _isdescriptionFocused, // width: isDesktop // ? MediaQuery.of(context).size.width * 0.38 // : MediaQuery.of(context).size.width * 0.85, @@ -2972,7 +3150,7 @@ class CreateNewPlansState extends State { child: SizedBox( height: 55, child: TextField( - focusNode: _descriptionFocusNode, + focusNode: focusNodes["descriptionFocusNode"], controller: _descriptionController, maxLines: 2, keyboardType: TextInputType.multiline, @@ -3059,7 +3237,7 @@ class CreateNewPlansState extends State { width: isDesktop ? MediaQuery.of(context).size.width * 0.2 : 180, height: 35, child: TextField( - focusNode: _tripTitleFocusNode, + // focusNode: _tripTitleFocusNode, controller: _tripTitleController, // style: TextStyle(fontSize: 12), style: GoogleFonts.poppins( diff --git a/lib/widgets/custom_text_field.dart b/lib/widgets/custom_text_field.dart index 8254c07..1aeed1c 100644 --- a/lib/widgets/custom_text_field.dart +++ b/lib/widgets/custom_text_field.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:frontend/utils/colorOpcity.dart'; +import '../utils/auth_utils.dart'; + class CustomTextFieldWrapper extends StatefulWidget { final Widget child; final bool isFocused; @@ -30,6 +32,28 @@ class CustomTextFieldWrapper extends StatefulWidget { } class _CustomTextFieldWrapperState extends State { + Color? layoutColor; + + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } + + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + Color getColorWithOpacity(Color color, double opacity) { final int alpha = (opacity * 255).round().clamp(0, 255); return Color.fromARGB( @@ -43,22 +67,23 @@ class _CustomTextFieldWrapperState extends State { @override Widget build(BuildContext context) { return Container( - width: widget.width ?? // Use custom width if provided, else default + width: + widget.width ?? // Use custom width if provided, else default (widget.isDesktop ? MediaQuery.of(context).size.width * 0.3 - : MediaQuery.of(context).size.width * 0.85), + : MediaQuery.of(context).size.width * 0.88), padding: widget.padding, decoration: BoxDecoration( - color: widget.isFocused - ? (widget.layoutColor ?? widget.color) - : widget.color, + // color: widget.isFocused + // ? (widget.layoutColor ?? widget.color) + // : widget.color, + color: Colors.white, borderRadius: widget.borderRadius ?? BorderRadius.circular(8), border: Border.all( - color: widget.isFocused - ? (widget.layoutColor ?? Colors.blueAccent) - : Color(0xFFF5F5F5), - width: widget.isFocused ? 1.5 : 1.5, + color: widget.isFocused ? layoutColor! : Color(0xFFD6D5E6), + // color: widget.isFocused ? Color(0xFF78B4FC) : Color(0xFFD6D5E6), + width: widget.isFocused ? 1.0 : 0.5, ), // boxShadow: widget.isFocused // ? [ diff --git a/lib/widgets/custom_text_itnerary_sub.dart b/lib/widgets/custom_text_itnerary_sub.dart index 9fe0251..efe58ac 100644 --- a/lib/widgets/custom_text_itnerary_sub.dart +++ b/lib/widgets/custom_text_itnerary_sub.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import '../utils/auth_utils.dart'; + class CustomTextFieldItnerarySubWrapper extends StatefulWidget { final Widget child; final bool isFocused; @@ -21,36 +23,64 @@ class CustomTextFieldItnerarySubWrapper extends StatefulWidget { }); @override - _CustomTextFieldItnerarySubWrapperState createState() => _CustomTextFieldItnerarySubWrapperState(); + _CustomTextFieldItnerarySubWrapperState createState() => + _CustomTextFieldItnerarySubWrapperState(); } -class _CustomTextFieldItnerarySubWrapperState extends State { +class _CustomTextFieldItnerarySubWrapperState + extends State { + Color? layoutColor; + + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + } + + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + @override Widget build(BuildContext context) { return Container( - width: widget.width ?? // Use custom width if provided, else default + width: + widget.width ?? // Use custom width if provided, else default (widget.isDesktop ? MediaQuery.of(context).size.width * 0.15 : MediaQuery.of(context).size.width * 0.8), padding: widget.padding, decoration: BoxDecoration( - color: widget.color, borderRadius: BorderRadius.circular(10), - border: Border.all( - color: widget.isFocused ? Color(0xFF78B4FC) : Color(0xFFD6D5E6), - width: widget.isFocused ? 2.0 : 0.5, - ), - boxShadow: widget.isFocused - ? [ - BoxShadow( - color: Color.fromRGBO(120, 180, 252, 0.3), - blurRadius: 10, - spreadRadius: 2, - offset: Offset(0, 4), + color: Colors.white, - ), - ] - : [], + border: Border.all( + color: widget.isFocused ? layoutColor! : Color(0xFFD6D5E6), + // color: widget.isFocused ? Color(0xFF78B4FC) : Color(0xFFD6D5E6), + width: widget.isFocused ? 1.0 : 0.5, + ), + boxShadow: + widget.isFocused + ? [ + BoxShadow( + color: Colors.white, + // color: Color.fromRGBO(120, 180, 252, 0.3), + blurRadius: 10, + spreadRadius: 2, + offset: Offset(0, 4), + ), + ] + : [], ), child: widget.child, ); From e33af3cd8a50095a3970c137164832bed86887fa Mon Sep 17 00:00:00 2001 From: venbaittech Date: Fri, 20 Jun 2025 14:44:50 +0530 Subject: [PATCH 2/2] travelAgentLst --- lib/Screens/allTrips/travel_agent_list.dart | 4 +- .../authentication/login/login_widget.dart | 64 +- lib/Screens/itnerary/accomodations.dart | 16 +- lib/Screens/itnerary/flights.dart | 780 ++++++++++++------ lib/Screens/itnerary/forex.dart | 131 +-- lib/Screens/itnerary/insurance.dart | 151 +++- .../forexDetails.dart | 0 .../{forex => perdiem_amount}/forex_list.dart | 0 lib/Screens/plans/create_plans.dart | 260 +++++- lib/app.dart | 4 +- lib/config/apiUrl.dart | 4 +- lib/routes/custom_router.dart | 12 +- lib/widgets/custom_text_field.dart | 27 +- 13 files changed, 1013 insertions(+), 440 deletions(-) rename lib/Screens/{forex => perdiem_amount}/forexDetails.dart (100%) rename lib/Screens/{forex => perdiem_amount}/forex_list.dart (100%) diff --git a/lib/Screens/allTrips/travel_agent_list.dart b/lib/Screens/allTrips/travel_agent_list.dart index ef90d8e..66243f3 100644 --- a/lib/Screens/allTrips/travel_agent_list.dart +++ b/lib/Screens/allTrips/travel_agent_list.dart @@ -216,8 +216,8 @@ class _TravelAgentListPlansState extends State { if (response.statusCode == 200) { final data = json.decode(response.body); - List plansJson = []; - // List plansJson = data['data']; + // List plansJson = []; + List plansJson = data['data']; return plansJson.map((json) => Plan.fromJson(json)).toList(); } else { throw Exception('Failed to load plans'); diff --git a/lib/Screens/authentication/login/login_widget.dart b/lib/Screens/authentication/login/login_widget.dart index 783cbc8..400c647 100644 --- a/lib/Screens/authentication/login/login_widget.dart +++ b/lib/Screens/authentication/login/login_widget.dart @@ -30,6 +30,8 @@ class _LoginWidgetState extends State { final ApiService apiService = ApiService(); bool _moved = false; + bool _isLoading = false; + final _formKey = GlobalKey(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); @@ -103,6 +105,10 @@ class _LoginWidgetState extends State { Future _login(BuildContext context) async { if (_formKey.currentState!.validate()) { + setState(() { + _isLoading = true; + }); + const String url = '$apiUrl/auth/login'; try { @@ -193,6 +199,10 @@ class _LoginWidgetState extends State { fontSize: 16.0, webBgColor: "linear-gradient(to right, #dc1c13, #dc1c13)", ); + } finally { + setState(() { + _isLoading = false; + }); } } } @@ -619,7 +629,13 @@ class _LoginWidgetState extends State { children: [ Expanded( child: ElevatedButton( - onPressed: () => _login(context), + // onPressed: () => _login(context), + onPressed: + _isLoading + ? null + : () => _login( + context, + ), // disable when loading style: ElevatedButton.styleFrom( backgroundColor: Color( 0xFF12B24B, @@ -639,23 +655,35 @@ class _LoginWidgetState extends State { horizontal: 24, vertical: 5, ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Sign In", - style: GoogleFonts.poppins( - fontWeight: FontWeight.w800, - fontSize: 13.5, - ), - ), - SizedBox(width: 3), - Icon( - Icons.arrow_forward_sharp, - color: Colors.white, - ), - ], - ), + child: + _isLoading + ? SizedBox( + height: 20, + width: 20, + child: + CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ), + ) + : Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Sign In", + style: GoogleFonts.poppins( + fontWeight: + FontWeight.w800, + fontSize: 13.5, + ), + ), + SizedBox(width: 3), + Icon( + Icons.arrow_forward_sharp, + color: Colors.white, + ), + ], + ), ), ), ), diff --git a/lib/Screens/itnerary/accomodations.dart b/lib/Screens/itnerary/accomodations.dart index 0cc5201..6187eb9 100644 --- a/lib/Screens/itnerary/accomodations.dart +++ b/lib/Screens/itnerary/accomodations.dart @@ -763,7 +763,10 @@ class _AccomodationScreenState extends State { child: SizedBox( height: 40, child: GestureDetector( - onTap: () => _selectCheckInDate(context), + onTap: () { + _checkInFocusNode.requestFocus(); + _selectCheckInDate(context); + }, child: AbsorbPointer( child: TextField( focusNode: _checkInFocusNode, @@ -816,6 +819,7 @@ class _AccomodationScreenState extends State { height: 40, child: GestureDetector( onTap: () { + _checkInTimeFocusNode.requestFocus(); _checkInTimeController.text = ""; _selectCheckInTime(context); }, @@ -870,7 +874,10 @@ class _AccomodationScreenState extends State { child: SizedBox( height: 40, child: GestureDetector( - onTap: () => _selectCheckOutDate(context), + onTap: () { + _checkOutFocusNode.requestFocus(); + _selectCheckOutDate(context); + }, child: AbsorbPointer( child: TextField( focusNode: _checkOutFocusNode, @@ -922,7 +929,10 @@ class _AccomodationScreenState extends State { child: SizedBox( height: 40, child: GestureDetector( - onTap: () => _selectCheckOutTime(context), + onTap: () { + _checkOutTimeFocusNode.requestFocus(); + _selectCheckOutTime(context); + }, child: AbsorbPointer( child: TextField( focusNode: _checkOutTimeFocusNode, diff --git a/lib/Screens/itnerary/flights.dart b/lib/Screens/itnerary/flights.dart index 12ec138..7e9d9b6 100644 --- a/lib/Screens/itnerary/flights.dart +++ b/lib/Screens/itnerary/flights.dart @@ -5,6 +5,7 @@ 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_radio_button.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; @@ -64,6 +65,9 @@ class FlightScreenState extends State { String? selectedvisa_available; int multiTripRowCount = 1; + // Color? layoutColor; + Color layoutColor = Colors.grey; + List dataHeader = [ "_tripType", "_class", @@ -89,7 +93,9 @@ class FlightScreenState extends State { @override void initState() { super.initState(); - + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); print("TripType - ${widget.tripType}"); // final newTripType = widget.tripTypeNotifier.value; @@ -280,6 +286,24 @@ class FlightScreenState extends State { 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-----------------"); @@ -982,7 +1006,9 @@ class FlightScreenState extends State { return [ CustomTextFieldWrapper( // isFocused: _tripTypeFocused, - isFocused: focusStates["_tripType1Focused"] ?? false, + // 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( @@ -1008,8 +1034,35 @@ class FlightScreenState extends State { .toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + // 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) { @@ -1427,7 +1480,9 @@ class FlightScreenState extends State { SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( // isFocused: _fromFocus, - isFocused: focusStates["_from${index}Focused"] ?? false, + // isFocused: focusStates["_from${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), // isFocused: focusStates["_from${fieldIndex}Focused"] ?? false, isDesktop: isDesktop, child: SizedBox( @@ -1548,9 +1603,38 @@ class FlightScreenState extends State { items: countryMap.values.toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + 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: 1, + horizontal: 10, + vertical: 5, ), ), ), @@ -1652,160 +1736,214 @@ class FlightScreenState extends State { ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_to${index}Focused"] ?? false, + // 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()) - : DropdownSearch( - 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, + : 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( + 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), ), - ), - 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, + menuProps: MenuProps( + backgroundColor: Colors.white, ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, + 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: [ - Text( - city, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), + 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( - code, + airport, style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, + fontSize: 11, + color: Colors.grey, + overflow: TextOverflow.ellipsis, ), ), ], ), - 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, + ), ), - ); - }, - // 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: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + ), + + // 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]!; + } + }); + }, ), ), - - // 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]!; - } - }); - }, ), ), ), @@ -1885,74 +2023,119 @@ class FlightScreenState extends State { ), SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_class${index}Focused"] ?? false, + // isFocused: focusStates["_class${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, child: SizedBox( - height: 35, + height: 40, width: double.infinity, - child: DropdownSearch>( - items: purposeList.cast>(), - selectedItem: purposeList.firstWhere( - (item) => item['dropdown_key'] == selectedClasses[index], - 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: 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>( + items: purposeList.cast>(), + selectedItem: purposeList.firstWhere( + (item) => item['dropdown_key'] == selectedClasses[index], + 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["_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, + ), ), - child: Text( - item['dropdown_value'] ?? '', + ), + 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, ), - ), - ); - }, - ), - dropdownDecoratorProps: const DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), + ); + }, + onChanged: + purposeList.isNotEmpty + ? (Map? newValue) { + setState(() { + selectedClasses[index] = + newValue?['dropdown_key']; + print( + "Selected Class: ${selectedClasses[index]}", + ); + }); + } + : null, ), ), - 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? newValue) { - setState(() { - selectedClasses[index] = newValue?['dropdown_key']; - print("Selected Class: ${selectedClasses[index]}"); - }); - } - : null, ), ), ), @@ -1987,7 +2170,10 @@ class FlightScreenState extends State { child: SizedBox( height: 40, child: GestureDetector( - onTap: () => _selectCheckOutDate(context), + onTap: () { + focusNodes["_date${index}FocusNode"]?.requestFocus(); + _selectCheckOutDate(context); + }, child: AbsorbPointer( child: TextField( focusNode: focusNodes["_date${index}FocusNode"], @@ -1995,13 +2181,44 @@ class FlightScreenState extends State { controller: textControllers["_date${index}Controller"], readOnly: true, style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( + decoration: InputDecoration( labelText: "Select Date", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), - suffixIcon: Icon( + // 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, @@ -2042,6 +2259,7 @@ class FlightScreenState extends State { height: 40, child: GestureDetector( onTap: () { + focusNodes["_time${index}FocusNode"]?.requestFocus(); textControllers["_time${index}Controller"]?.text = ""; _clearError("time_$index"); // validateTimeDifference(index); @@ -2214,74 +2432,116 @@ class FlightScreenState extends State { SizedBox(height: 5), CustomTextFieldItnerarySubWrapper( // use same wrapper as class - isFocused: focusStates["_visa1Focused"] ?? false, + // isFocused: focusStates["_visa1Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, child: SizedBox( height: 35, width: double.infinity, - child: DropdownSearch>( - items: visa_available.cast>(), - 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: Focus( + focusNode: focusNodes["_visa1FocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["_visa1Focused"] = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_visa1FocusNode"]?.requestFocus(); + }, + child: DropdownSearch>( + items: visa_available.cast>(), + 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, + ), ), - child: Text( - item['dropdown_value'] ?? '', + ), + 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, ), - ), - ); - }, - ), - dropdownDecoratorProps: const DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), + ); + }, + onChanged: + visa_available.isNotEmpty + ? (Map? newValue) { + setState(() { + selectedvisa_available = + newValue?['dropdown_key']; + print("Selected Visa: $selectedvisa_available"); + }); + } + : null, ), ), - 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? newValue) { - setState(() { - selectedvisa_available = newValue?['dropdown_key']; - print("Selected Visa: $selectedvisa_available"); - }); - } - : null, ), ), ), diff --git a/lib/Screens/itnerary/forex.dart b/lib/Screens/itnerary/forex.dart index b880436..5a8c4f7 100644 --- a/lib/Screens/itnerary/forex.dart +++ b/lib/Screens/itnerary/forex.dart @@ -135,7 +135,6 @@ class _ForexScreenState extends State { String? selectedQuotedAmount; int? selectedCashPercent; int? selectedCardPercent; - bool userEdited = false; Map get forexData { @@ -399,7 +398,10 @@ class _ForexScreenState extends State { focusStates[field] = false; } } - print("textControllers - $textControllers"); + + print("Focus States KeysII: ${focusStates.keys.toList()}"); + print("Focus Nodes KeysII: ${focusNodes.keys.toList()}"); + print("Text Controllers KeysII: ${textControllers.keys.toList()}"); // Add focus listeners focusNodes.forEach((key, focusNode) { @@ -1347,64 +1349,85 @@ class _ForexScreenState extends State { // ), // ), CustomTextFieldForexWrapper( - isFocused: focusStates["_countries"] ?? false, + isFocused: focusStates["_countriesFocused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, - child: DropdownSearch( - selectedItem: countryMap[selectedCountry], - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - constraints: BoxConstraints(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, - contentPadding: EdgeInsets.symmetric(horizontal: 1), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select ", - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ), - ), - onChanged: (String? newValue) { + child: Focus( + focusNode: focusNodes["_countriesFocusNode"], + onFocusChange: (hasFocus) { setState(() { - // Find the country_code based on selected country_name - selectedCountry = - countryMap.entries - .firstWhere((entry) => entry.value == newValue) - .key; - _onCountryChanged(selectedCountry); + focusStates["_countriesFocused"] = hasFocus; }); }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_countriesFocusNode"]?.requestFocus(); + }, + child: DropdownSearch( + selectedItem: countryMap[selectedCountry], + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints(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, + contentPadding: EdgeInsets.symmetric(horizontal: 1), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select ", + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), + ), + onChanged: (String? newValue) { + setState(() { + // Find the country_code based on selected country_name + selectedCountry = + countryMap.entries + .firstWhere( + (entry) => entry.value == newValue, + ) + .key; + _onCountryChanged(selectedCountry); + }); + }, + ), + ), ), ), ), diff --git a/lib/Screens/itnerary/insurance.dart b/lib/Screens/itnerary/insurance.dart index 3784e7a..3e19de0 100644 --- a/lib/Screens/itnerary/insurance.dart +++ b/lib/Screens/itnerary/insurance.dart @@ -4,6 +4,7 @@ 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_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; @@ -53,6 +54,8 @@ class _InsuranceScreenState extends State { late TextEditingController _nomineerelationController = TextEditingController(); + Color layoutColor = Colors.grey; + bool _isHotelNameFocused = false; bool _startDateFocus = false; bool _endDateFocus = false; @@ -63,6 +66,18 @@ class _InsuranceScreenState extends State { String? selectedInsuranceType; Map errorMessages = {}; + Map focusNodes = {}; + Map focusStates = {}; + + List dataHeader = [ + "type_of_insurance", + "start_date", + "end_date", + "comments", + "nominee_name", + "nominee_dob", + "nominee_relationship", + ]; Map get InsuranceData { Map data = { @@ -94,33 +109,27 @@ class _InsuranceScreenState extends State { @override void initState() { super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + focusNodes.clear(); + focusStates.clear(); - _hotelNameFocusNode.addListener(() { - setState(() { - _isHotelNameFocused = _hotelNameFocusNode.hasFocus; - }); - }); - _endDateFocusNode.addListener(() { - setState(() { - _endDateFocus = _endDateFocusNode.hasFocus; - }); - }); - _startDateFocusNode.addListener(() { - setState(() { - _startDateFocus = _startDateFocusNode.hasFocus; - }); - }); - _commentsFocusNode.addListener(() { - setState(() { - _commentsFocus = _commentsFocusNode.hasFocus; - }); - }); + // Initialize fields dynamically + for (var field in dataHeader) { + focusNodes["${field}FocusNode"] = FocusNode(); + focusStates["${field}Focused"] = false; + } - _nomineeFocusNode.addListener(() { - setState(() { - _nomineeFocus = _nomineeFocusNode.hasFocus; + for (var key in focusNodes.keys) { + _addFocusListener(focusNodes[key]!, (focus) { + setState(() { + focusStates[key.replaceFirst("FocusNode", "Focused")] = focus; + }); }); - }); + } + print("Focus Nodes Keys: ${focusNodes.keys.toList()}"); + print("Focus States Keys: ${focusStates.keys.toList()}"); _insuranceCommentsController = TextEditingController( text: widget.selectedItem?["comments"] ?? "", @@ -181,6 +190,16 @@ class _InsuranceScreenState extends State { }); } + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + Map getFlightTripDateRange( List> flightData, ) { @@ -285,6 +304,11 @@ class _InsuranceScreenState extends State { @override void dispose() { + // Dispose all dynamically created FocusNodes + for (var node in focusNodes.values) { + node.dispose(); + } + _tripTypeFocusNode.dispose(); _tripTypeController.dispose(); _startDateController.dispose(); @@ -769,7 +793,9 @@ class _InsuranceScreenState extends State { // ), // ▼ Dropdown Wrapper ▼ CustomTextFieldWrapper( - isFocused: _isHotelNameFocused, + // isFocused: _isHotelNameFocused, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null, child: SizedBox( @@ -802,14 +828,45 @@ class _InsuranceScreenState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( + // border: InputBorder.none, // No underline + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["type_of_insuranceFocusNode"] ?? false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["type_of_insuranceFocusNode"] ?? 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: 10, + vertical: 5, ), ), + // dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric( + // horizontal: 10, + // vertical: 10, + // ), + // ), ), dropdownBuilder: (context, selectedItem) { if (selectedItem == null || selectedItem.isEmpty) { @@ -897,13 +954,15 @@ class _InsuranceScreenState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _startDateFocus, + // isFocused: _startDateFocus, + isFocused: focusStates["start_dateFocused"] ?? false, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null, child: SizedBox( height: 40, child: GestureDetector( onTap: () async { + focusNodes["start_dateFocusNode"]?.requestFocus(); await _selectCheckOutDate(context); if (_startDateController.text.isNotEmpty) { setState(() { @@ -915,7 +974,8 @@ class _InsuranceScreenState extends State { }, child: AbsorbPointer( child: TextField( - focusNode: _startDateFocusNode, + // focusNode: _startDateFocusNode, + focusNode: focusNodes["start_dateFocusNode"], controller: _startDateController, readOnly: true, style: const TextStyle(fontSize: 12), @@ -956,13 +1016,14 @@ class _InsuranceScreenState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _endDateFocus, + isFocused: focusStates["end_dateFocused"] ?? false, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null, child: SizedBox( height: 40, child: GestureDetector( onTap: () async { + focusNodes["end_dateFocusNode"]?.requestFocus(); await _selectEndCheckOutDate(context); if (_endDateController.text.isNotEmpty) { @@ -985,7 +1046,8 @@ class _InsuranceScreenState extends State { }, child: AbsorbPointer( child: TextField( - focusNode: _endDateFocusNode, + // focusNode: _endDateFocusNode, + focusNode: focusNodes["end_dateFocusNode"], controller: _endDateController, readOnly: true, style: const TextStyle(fontSize: 12), @@ -1108,7 +1170,8 @@ class _InsuranceScreenState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _nomineeFocus, + // isFocused: _nomineeFocus, + isFocused: focusStates["nominee_nameFocused"] ?? false, isDesktop: isDesktop, // width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null, @@ -1116,7 +1179,9 @@ class _InsuranceScreenState extends State { child: SizedBox( height: 40, child: TextField( - focusNode: _nomineeFocusNode, + focusNode: focusNodes["nominee_nameFocusNode"], + + // focusNode: _nomineeFocusNode, controller: _nomineeController, style: TextStyle(fontSize: 12), decoration: InputDecoration( @@ -1150,7 +1215,7 @@ class _InsuranceScreenState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _startDateFocus, + isFocused: focusStates["nominee_dobFocused"] ?? false, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null, // width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, @@ -1158,6 +1223,7 @@ class _InsuranceScreenState extends State { height: 40, child: GestureDetector( onTap: () async { + focusNodes["nominee_dobFocusNode"]?.requestFocus(); await _selectCheckDOBOutDate(context); // await _selectDateOfBirth(context); if (_dateOfBirthController.text.isNotEmpty) { @@ -1170,7 +1236,7 @@ class _InsuranceScreenState extends State { }, child: AbsorbPointer( child: TextField( - focusNode: _startDateFocusNode, + focusNode: focusNodes["nominee_dobFocusNode"], controller: _dateOfBirthController, readOnly: true, style: const TextStyle(fontSize: 12), @@ -1213,7 +1279,7 @@ class _InsuranceScreenState extends State { // CustomTextFieldWrapper( - isFocused: false, + isFocused: focusStates["nominee_relationshipFocused"] ?? false, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null, // width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null, @@ -1221,7 +1287,7 @@ class _InsuranceScreenState extends State { child: SizedBox( height: 40, child: TextField( - // focusNode: _nomineeFocusNode, + focusNode: focusNodes["nominee_relationshipFocusNode"], controller: _nomineerelationController, style: TextStyle(fontSize: 12), decoration: InputDecoration( @@ -1260,7 +1326,9 @@ class _InsuranceScreenState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _commentsFocus, // Dropdown doesn't use focus + isFocused: + focusStates["commentsFocused"] ?? + false, // Dropdown doesn't use focus isDesktop: isDesktop, width: isDesktop @@ -1269,7 +1337,8 @@ class _InsuranceScreenState extends State { child: SizedBox( height: 40, child: TextField( - focusNode: _commentsFocusNode, + // focusNode: _commentsFocusNode, + focusNode: focusNodes["commentsFocusNode"], controller: _insuranceCommentsController, style: TextStyle(fontSize: 12), decoration: InputDecoration( diff --git a/lib/Screens/forex/forexDetails.dart b/lib/Screens/perdiem_amount/forexDetails.dart similarity index 100% rename from lib/Screens/forex/forexDetails.dart rename to lib/Screens/perdiem_amount/forexDetails.dart diff --git a/lib/Screens/forex/forex_list.dart b/lib/Screens/perdiem_amount/forex_list.dart similarity index 100% rename from lib/Screens/forex/forex_list.dart rename to lib/Screens/perdiem_amount/forex_list.dart diff --git a/lib/Screens/plans/create_plans.dart b/lib/Screens/plans/create_plans.dart index 5e23763..8218b5d 100644 --- a/lib/Screens/plans/create_plans.dart +++ b/lib/Screens/plans/create_plans.dart @@ -389,6 +389,8 @@ class CreateNewPlansState extends State { // bool _isdescriptionFocused = false; // bool _isTripTitleFocused = false; + Color? layoutColor; + late String _selectedOption = "Option 1"; // late String? _selectedIsBillable = "Billable"; @@ -537,6 +539,9 @@ class CreateNewPlansState extends State { void initState() { super.initState(); print("approverStatus - ${widget.approverStatus}"); + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); if (widget.approverStatus == "Approval pending") { print("Status approver - Approval Pending"); @@ -580,6 +585,17 @@ class CreateNewPlansState extends State { handleUpdateData(); } + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + @override void dispose() { for (var node in focusNodes.values) { @@ -1332,22 +1348,22 @@ class CreateNewPlansState extends State { if (response.statusCode == 200) { print("Plan submitted successfully!"); print("Response: ${response.body}"); - - final currentUri = - GoRouterState.of( - context, - ).uri.toString(); // ✅ safer than `.location` - print("currentUri - $currentUri"); - - if (currentUri == "/allTrips/trips") { - context.go('/listAllPlan'); - } else if (currentUri == "/createPlan") { - context.go('/listPlan'); - } else { - widget.isApprover - ? context.go('/approvallist') - : context.go('/listPlan'); - } + // + // final currentUri = + // GoRouterState.of( + // context, + // ).uri.toString(); // ✅ safer than `.location` + // print("currentUri - $currentUri"); + // + // if (currentUri == "/allTrips/trips") { + // context.go('/listAllPlan'); + // } else if (currentUri == "/createPlan") { + // context.go('/listPlan'); + // } else { + // widget.isApprover + // ? context.go('/approvallist') + // : context.go('/listPlan'); + // } } else { print("Failed to submit plan. Status: ${response.statusCode}"); print("Error: ${response.body}"); @@ -1804,10 +1820,13 @@ class CreateNewPlansState extends State { SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: focusStates["trip_typeFocused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + // isFocused: focusStates["trip_typeFocused"] ?? false, isDesktop: widget.isDesktop, child: SizedBox( height: 35, + // width: double.infinity, width: double.infinity, child: Focus( focusNode: focusNodes["trip_typeFocusNode"], @@ -1825,7 +1844,9 @@ class CreateNewPlansState extends State { popupProps: PopupProps.menu( showSearchBox: false, // Optionally enable search fit: FlexFit.loose, + menuProps: const MenuProps(backgroundColor: Colors.white), + itemBuilder: (context, item, isSelected) { return Padding( padding: const EdgeInsets.symmetric( @@ -1842,16 +1863,42 @@ class CreateNewPlansState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, // No underline - contentPadding: EdgeInsets.symmetric( + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, // No underline + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["trip_typeFocused"] ?? false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["trip_typeFocused"] ?? 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( @@ -1951,7 +1998,9 @@ class CreateNewPlansState extends State { SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: focusStates["is_billableFocused"] ?? false, + // isFocused: focusStates["is_billableFocused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), width: widget.isDesktop ? MediaQuery.of(context).size.width * 0.2 @@ -1994,10 +2043,33 @@ class CreateNewPlansState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["is_billableFocused"] ?? false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["is_billableFocused"] ?? 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, ), @@ -2225,9 +2297,10 @@ class CreateNewPlansState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: - focusStates["cost_center_idFocused"] ?? - false, // Dropdown doesn't use focus + // isFocused: focusStates["cost_center_idFocused"] ?? + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + isDesktop: widget.isDesktop, child: SizedBox( height: 35, @@ -2242,6 +2315,7 @@ class CreateNewPlansState extends State { ) : Focus( focusNode: focusNodes["cost_center_idFocusNode"], + onFocusChange: (hasFocus) { setState(() { focusStates["cost_center_idFocused"] = hasFocus; @@ -2295,7 +2369,35 @@ class CreateNewPlansState extends State { items: costCenterMap.values.toList(), // just names dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["cost_center_idFocused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["cost_center_idFocused"] ?? + 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: 1), contentPadding: EdgeInsets.symmetric( horizontal: 10, @@ -2400,7 +2502,9 @@ class CreateNewPlansState extends State { isDesktop ? MediaQuery.of(context).size.width * 0.2 : MediaQuery.of(context).size.width * 0.88, - isFocused: focusStates["purpose_of_travelFocused"] ?? false, + // isFocused: focusStates["purpose_of_travelFocused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: widget.isDesktop, child: SizedBox( @@ -2472,11 +2576,39 @@ class CreateNewPlansState extends State { ), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["purpose_of_travelFocused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["purpose_of_travelFocused"] ?? + 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, ), - border: InputBorder.none, ), ), onChanged: @@ -2582,7 +2714,9 @@ class CreateNewPlansState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: focusStates["functional_departmentFocused"] ?? false, + // isFocused: focusStates["functional_departmentFocused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: widget.isDesktop, width: isDesktop @@ -2666,7 +2800,35 @@ class CreateNewPlansState extends State { horizontal: 10, vertical: 5, ), - border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["functional_departmentFocused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["functional_departmentFocused"] ?? + false) + ? layoutColor! + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor!, + width: 1, + ), + ), ), ), onChanged: @@ -2737,8 +2899,9 @@ class CreateNewPlansState extends State { return [ CustomTextFieldWrapper( - isFocused: focusStates["trip_plannedFocused"] ?? false, - + // isFocused: focusStates["trip_plannedFocused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, layoutColor: widget.layoutColor, child: SizedBox( @@ -2766,6 +2929,7 @@ class CreateNewPlansState extends State { popupProps: PopupProps.menu( showSearchBox: false, menuProps: const MenuProps(backgroundColor: Colors.white), + constraints: BoxConstraints(maxHeight: 100), itemBuilder: (context, item, isSelected) => Padding( @@ -2781,7 +2945,31 @@ class CreateNewPlansState extends State { ), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["trip_typeFocused"] ?? false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["trip_plannedFocused"] ?? 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, diff --git a/lib/app.dart b/lib/app.dart index f89ee60..3839acd 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; +// import 'package:flutter/rendering.dart'; import 'dart:html' as html; import 'package:frontend/config/apiUrl.dart'; // 1 newly added import 'package:frontend/services/apiService.dart'; @@ -31,7 +31,7 @@ class _MyAppState extends State { @override void initState() { super.initState(); - SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here + // SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here if (kIsWeb) { final uri = Uri.parse(html.window.location.href); print("URI - $uri"); diff --git a/lib/config/apiUrl.dart b/lib/config/apiUrl.dart index eb751b8..7139bea 100644 --- a/lib/config/apiUrl.dart +++ b/lib/config/apiUrl.dart @@ -1,3 +1,3 @@ //api url -const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be'; -// const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; +// const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be'; +const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; diff --git a/lib/routes/custom_router.dart b/lib/routes/custom_router.dart index 5e72184..6bc6568 100644 --- a/lib/routes/custom_router.dart +++ b/lib/routes/custom_router.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:frontend/Screens/authentication/login/login_page.dart'; import 'package:frontend/Screens/authentication/loginPage1.dart'; import 'package:frontend/Screens/dashboard/home_page.dart'; -import 'package:frontend/Screens/forex/forex_list.dart'; import 'package:frontend/Screens/myTemplates/templatesList.dart'; import 'package:frontend/Screens/organization/orgSetup.dart'; import 'package:frontend/Screens/organization/org_List.dart'; @@ -26,6 +25,7 @@ import '../Screens/group/groupList.dart'; import '../Screens/myTemplates/template.dart'; import '../Screens/myTemplates/templateForex.dart'; import '../Screens/myTemplates/templateTest.dart'; +import '../Screens/perdiem_amount/forex_list.dart'; import '../Screens/userManagement/create_user/create_user.dart'; import '../Screens/department/department_list.dart'; import '../Screens/costCenter/costCenter_list.dart'; @@ -150,10 +150,7 @@ final GoRouter router = GoRouter( pageBuilder: (context, state) => MaterialPage(child: Group.fromState(state)), ), - GoRoute( - path: '/report', - builder: (context, state) => ReportList(), - ), + GoRoute(path: '/report', builder: (context, state) => ReportList()), GoRoute( path: '/advancePurchase', builder: (context, state) => AdvancePurchase(), @@ -162,10 +159,7 @@ final GoRouter router = GoRouter( path: '/misservicesAnalysis', builder: (context, state) => ServicesAnalysis(), ), - GoRoute( - path: '/misAirReport', - builder: (context, state) => MISair(), - ), + GoRoute(path: '/misAirReport', builder: (context, state) => MISair()), GoRoute( path: '/misHotelReport', builder: (context, state) => MIShotel(), diff --git a/lib/widgets/custom_text_field.dart b/lib/widgets/custom_text_field.dart index 1aeed1c..eebc4c7 100644 --- a/lib/widgets/custom_text_field.dart +++ b/lib/widgets/custom_text_field.dart @@ -85,19 +85,20 @@ class _CustomTextFieldWrapperState extends State { // color: widget.isFocused ? Color(0xFF78B4FC) : Color(0xFFD6D5E6), width: widget.isFocused ? 1.0 : 0.5, ), - // boxShadow: widget.isFocused - // ? [ - // BoxShadow( - // // color: Color.fromRGBO(120, 180, 252, 0.3), - // // color: widget.isFocused - // // ? (widget.layoutColor ?? Colors.red).withAlpha(204) - // // : Color(0xFFF5F5F5), - // blurRadius: 10, - // spreadRadius: 1, - // offset: Offset(0, 4), - // ), - // ] - // : [], + // boxShadow: + // widget.isFocused + // ? [ + // BoxShadow( + // color: widget.isFocused ? layoutColor! : Color(0xFFD6D5E6), + // // color: widget.isFocused + // // ? (widget.layoutColor ?? Colors.red).withAlpha(204) + // // : Color(0xFFF5F5F5), + // blurRadius: 10, + // spreadRadius: 1, + // offset: Offset(0, 4), + // ), + // ] + // : [], ), child: widget.child, );