diff --git a/lib/Screens/costCenter/costCenterDetails.dart b/lib/Screens/costCenter/costCenterDetails.dart index 12d24d3..697e3c8 100644 --- a/lib/Screens/costCenter/costCenterDetails.dart +++ b/lib/Screens/costCenter/costCenterDetails.dart @@ -36,11 +36,12 @@ class CostCenterDataState extends State { final ApiService apiService = ApiService(); Map? apiData; - final Map focusNodes = { - "name": FocusNode(), - "description": FocusNode(), - }; - + // final Map focusNodes = { + // "name": FocusNode(), + // "description": FocusNode(), + // }; + Map focusNodes = {}; + Map focusStates = {}; final Map controllers = {}; Map errorMessages = {}; @@ -70,6 +71,15 @@ class CostCenterDataState extends State { apiData = null; for (var field in dataHeader) { controllers[field] = TextEditingController(); + focusNodes["${field}FocusNode"] = FocusNode(); + focusStates["${field}Focused"] = false; + } + for (var key in focusNodes.keys) { + _addFocusListener(focusNodes[key]!, (focus) { + setState(() { + focusStates[key.replaceFirst("FocusNode", "Focused")] = focus; + }); + }); } if (widget.costcenterId != null) { @@ -89,8 +99,18 @@ class CostCenterDataState extends State { for (var controller in controllers.values) { controller.dispose(); } + for (var node in focusNodes.values) { + node.dispose(); + } super.dispose(); } + void _addFocusListener(FocusNode node, Function(bool) updateState) { + node.addListener(() { + setState(() { + updateState(node.hasFocus); + }); + }); + } void updateCostCenterDetails() { print("Inside Update Function - ${widget.costcenterData}"); @@ -129,10 +149,10 @@ class CostCenterDataState extends State { if (data[field] == null || data[field]!.trim().isEmpty) { errorMessages[field] = "Required"; - if (!hasFocused) { - focusNodes[field]?.requestFocus(); - hasFocused = true; - } + // if (!hasFocused) { + // focusNodes[field]?.requestFocus(); + // hasFocused = true; + // } } } @@ -258,14 +278,14 @@ class CostCenterDataState extends State { ), SizedBox(height: 5), CustomTextFieldForexWrapper( - isFocused: false, + isFocused: focusStates["nameFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: TextField( controller: controllers["name"], - focusNode: focusNodes["name"], + focusNode: focusNodes["nameFocusNode"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Name", @@ -300,14 +320,14 @@ class CostCenterDataState extends State { ), SizedBox(height: 5), CustomTextFieldForexWrapper( - isFocused: false, + isFocused: focusStates["descriptionFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 100, child: TextField( controller: controllers["description"], - focusNode: focusNodes["description"], + focusNode: focusNodes["descriptionFocusNode"], style: const TextStyle(fontSize: 12), maxLines: null, expands: true, diff --git a/lib/Screens/department/departmentDetails.dart b/lib/Screens/department/departmentDetails.dart index 4d461fb..dbb9e7a 100644 --- a/lib/Screens/department/departmentDetails.dart +++ b/lib/Screens/department/departmentDetails.dart @@ -36,26 +36,27 @@ class DepartmentDataState extends State { final ApiService apiService = ApiService(); Map? apiData; - final Map focusNodes = { - "name": FocusNode(), - "description": FocusNode(), - }; + // final Map focusNodes = { + // "name": FocusNode(), + // "description": FocusNode(), + // }; final Map controllers = {}; Map errorMessages = {}; - + Map focusNodes = {}; + Map focusStates = {}; String? selectedName; String? selectedDescription; String? userId; int? departmentDataId; late String isActive = "1"; - List dataHeader = ["name", "description"]; + List dataHeader = ["dropdown_value", "description"]; Map departmentDetails() { final data = { // "department_id": int.parse(departmentId), - "name": controllers["name"]?.text, + "dropdown_value": controllers["dropdown_value"]?.text, "description": controllers["description"]?.text, "created_by": userId, "is_active": isActive, @@ -70,6 +71,15 @@ class DepartmentDataState extends State { apiData = null; for (var field in dataHeader) { controllers[field] = TextEditingController(); + focusNodes["${field}FocusNode"] = FocusNode(); + focusStates["${field}Focused"] = false; + } + for (var key in focusNodes.keys) { + _addFocusListener(focusNodes[key]!, (focus) { + setState(() { + focusStates[key.replaceFirst("FocusNode", "Focused")] = focus; + }); + }); } if (widget.departmentId != null) { @@ -89,8 +99,18 @@ class DepartmentDataState extends State { for (var controller in controllers.values) { controller.dispose(); } + for (var node in focusNodes.values) { + node.dispose(); + } super.dispose(); } + void _addFocusListener(FocusNode node, Function(bool) updateState) { + node.addListener(() { + setState(() { + updateState(node.hasFocus); + }); + }); + } void updateDepartmentDetails() { print("Inside Update Function - ${widget.departmentData}"); @@ -99,10 +119,10 @@ class DepartmentDataState extends State { if (data == null) return; setState(() { - controllers['name']?.text = data['name'] ?? ''; - controllers['description']?.text = data['description'].toString(); + controllers['dropdown_value']?.text = data['dropdown_value'] ?? ''; + // controllers['description']?.text = data['description'].toString(); isActive = data["is_active"]; - final departmentId = int.tryParse(data['department_id'].toString()); + final departmentId = int.tryParse(data['id'].toString()); departmentDataId = departmentId; }); } @@ -117,11 +137,11 @@ class DepartmentDataState extends State { errorMessages.clear(); final data = { - "name": controllers["name"]?.text, - "description": controllers["description"]?.text, + "dropdown_value": controllers["dropdown_value"]?.text, + // "description": controllers["description"]?.text, }; - final requiredFields = ["name", "description"]; + final requiredFields = ["dropdown_value"]; bool hasFocused = false; // Check validation for each field @@ -129,10 +149,10 @@ class DepartmentDataState extends State { if (data[field] == null || data[field]!.trim().isEmpty) { errorMessages[field] = "Required"; - if (!hasFocused) { - focusNodes[field]?.requestFocus(); - hasFocused = true; - } + // if (!hasFocused) { + // focusNodes[field]?.requestFocus(); + // hasFocused = true; + // } } } @@ -165,7 +185,7 @@ class DepartmentDataState extends State { if (departmentDataId != null) { print("for edit department id - $departmentDataId"); apiUrldata = '$apiUrl/api/updateDepartment/$departmentDataId'; - departmentData["department_id"] = departmentDataId.toString(); + departmentData["id"] = departmentDataId.toString(); departmentData["updated_by"] = userId; (departmentData.containsKey("created_by")) ? departmentData.remove("created_by") @@ -261,14 +281,14 @@ class DepartmentDataState extends State { ), SizedBox(height: 5), CustomTextFieldForexWrapper( - isFocused: false, + isFocused: focusStates["dropdown_valueFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: TextField( - controller: controllers["name"], - focusNode: focusNodes["name"], + controller: controllers["dropdown_value"], + focusNode: focusNodes["dropdown_valueFocusNode"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Name", @@ -280,60 +300,60 @@ class DepartmentDataState extends State { ), ), ), - if (errorMessages["name"] != null) ...[ + if (errorMessages["dropdown_value"] != null) ...[ SizedBox(height: 5), // Space before error message Text( - errorMessages["name"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - SizedBox(height: 15), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Description *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldForexWrapper( - isFocused: false, - isDesktop: widget.isDesktop, - color: Colors.transparent, - child: SizedBox( - height: 100, - child: TextField( - controller: controllers["description"], - focusNode: focusNodes["description"], - style: const TextStyle(fontSize: 12), - maxLines: null, - expands: true, - decoration: const InputDecoration( - labelText: "Description", - labelStyle: TextStyle(fontSize: 11, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - ), - ), - ), - ), - if (errorMessages["description"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["description"]!, + errorMessages["dropdown_value"]!, style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), SizedBox(height: 15), + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Text( + // "Description *", + // style: GoogleFonts.poppins( + // fontSize: 12, + // fontWeight: FontWeight.w600, + // color: Color(0xFF575A74), + // ), + // ), + // SizedBox(height: 5), + // CustomTextFieldForexWrapper( + // isFocused: focusStates["descriptionFocused"] ?? false, + // isDesktop: widget.isDesktop, + // color: Colors.transparent, + // child: SizedBox( + // height: 100, + // child: TextField( + // controller: controllers["description"], + // focusNode: focusNodes["descriptionFocusNode"], + // style: const TextStyle(fontSize: 12), + // maxLines: null, + // expands: true, + // decoration: const InputDecoration( + // labelText: "Description", + // labelStyle: TextStyle(fontSize: 11, color: Colors.grey), + // floatingLabelBehavior: FloatingLabelBehavior.never, + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(vertical: 16), + // ), + // ), + // ), + // ), + // if (errorMessages["description"] != null) ...[ + // SizedBox(height: 5), // Space before error message + // Text( + // errorMessages["description"]!, + // style: TextStyle(color: Colors.red, fontSize: 12), + // ), + // ], + // ], + // ), + // SizedBox(height: 15), if (departmentDataId != null) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/Screens/department/department_list.dart b/lib/Screens/department/department_list.dart index 28737f9..8766693 100644 --- a/lib/Screens/department/department_list.dart +++ b/lib/Screens/department/department_list.dart @@ -180,13 +180,13 @@ class DepartmentListState extends State { allDepartment.where((object) { final isActiveStatus = object['is_active'] == "1" ? "active" : "inactive"; - return (object['department_id']?.toLowerCase().contains( + return (object['id']?.toLowerCase().contains( lowerQuery, ) ?? false) || - (object['name']?.toLowerCase().contains(lowerQuery) ?? false) || - (object['description']?.toLowerCase().contains(lowerQuery) ?? - false) || + (object['dropdown_value']?.toLowerCase().contains(lowerQuery) ?? false) || + // (object['description']?.toLowerCase().contains(lowerQuery) ?? + // false) || (isActiveStatus.contains(lowerQuery)); }).toList(); currentPage = 0; @@ -550,15 +550,15 @@ class DepartmentListState extends State { ), ), ), - DataColumn( - label: Text( - 'Description', - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w600, - ), - ), - ), + // DataColumn( + // label: Text( + // 'Description', + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w600, + // ), + // ), + // ), DataColumn( label: Text( 'Status', @@ -581,7 +581,7 @@ class DepartmentListState extends State { rows: paginatedDepartment.map((tableObject) { String departmentId = - tableObject['department_id'] + tableObject['id'] .toString(); // Get user ID bool isSelected = selectedDepartmentId == departmentId; @@ -590,24 +590,24 @@ class DepartmentListState extends State { cells: [ DataCell( Text( - tableObject['name'] ?? '', + tableObject['dropdown_value'] ?? '', style: TextStyle( fontSize: 13, fontFamily: "Inter", ), ), ), - DataCell( - Text( - tableObject['description'] ?? 'N/A', - style: TextStyle( - fontSize: 13, - fontFamily: "Inter", - ), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - ), + // DataCell( + // Text( + // tableObject['description'] ?? 'N/A', + // style: TextStyle( + // fontSize: 13, + // fontFamily: "Inter", + // ), + // softWrap: true, + // overflow: TextOverflow.ellipsis, + // ), + // ), DataCell( Text( tableObject['is_active'] == "1" @@ -645,7 +645,7 @@ class DepartmentListState extends State { // final usersData = await getUserDetails(userId); // final departmentId = int.tryParse( - tableObject['department_id'] + tableObject['id'] .toString(), ); @@ -716,7 +716,7 @@ class DepartmentListState extends State { MainAxisAlignment.spaceBetween, children: [ Text( - cardObject['name'] ?? 'N/A', + cardObject['dropdown_value'] ?? 'N/A', style: GoogleFonts.poppins( fontSize: 10, color: Colors.black87, @@ -738,7 +738,7 @@ class DepartmentListState extends State { // final usersData = await getUserDetails(userId); // final departmentId = int.tryParse( - cardObject['department_id'] + cardObject['id'] .toString(), ); @@ -852,37 +852,37 @@ class DepartmentListState extends State { SizedBox(height: 2), // Trip Id and Trip Name // Name - Row( - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - cardObject['description'] ?? '', - style: GoogleFonts.poppins( - fontSize: 10, - color: Colors.black87, - ), - ), - ], - ), - SizedBox(width: 10), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - cardObject['description'] ?? '', - style: GoogleFonts.poppins( - fontSize: 10, - color: Colors.black87, - ), - ), - ], - ), - ], - ), + // Row( + // children: [ + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // cardObject['description'] ?? '', + // style: GoogleFonts.poppins( + // fontSize: 10, + // color: Colors.black87, + // ), + // ), + // ], + // ), + // SizedBox(width: 10), + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // cardObject['description'] ?? '', + // style: GoogleFonts.poppins( + // fontSize: 10, + // color: Colors.black87, + // ), + // ), + // ], + // ), + // ], + // ), // Actions // Actions ], diff --git a/lib/Screens/hotels/hotelsDetails.dart b/lib/Screens/hotels/hotelsDetails.dart index a230726..4439c91 100644 --- a/lib/Screens/hotels/hotelsDetails.dart +++ b/lib/Screens/hotels/hotelsDetails.dart @@ -42,6 +42,8 @@ class HotelsDataState extends State { Map? apiData; final Map controllers = {}; Map errorMessages = {}; + Map focusNodes = {}; + Map focusStates = {}; List countryList = []; String? selectedCountry; @@ -83,6 +85,15 @@ class HotelsDataState extends State { apiData = null; for (var field in dataHeader) { controllers[field] = TextEditingController(); + focusNodes["${field}FocusNode"] = FocusNode(); + focusStates["${field}Focused"] = false; + } + for (var key in focusNodes.keys) { + _addFocusListener(focusNodes[key]!, (focus) { + setState(() { + focusStates[key.replaceFirst("FocusNode", "Focused")] = focus; + }); + }); } fetchCountries(); if (widget.hotelsId != null) { @@ -103,8 +114,18 @@ class HotelsDataState extends State { for (var controller in controllers.values) { controller.dispose(); } + for (var node in focusNodes.values) { + node.dispose(); + } super.dispose(); } + void _addFocusListener(FocusNode node, Function(bool) updateState) { + node.addListener(() { + setState(() { + updateState(node.hasFocus); + }); + }); + } void updateHotelsDetails() { print("Update - ${widget.hotelsData}"); @@ -312,12 +333,14 @@ class HotelsDataState extends State { ), SizedBox(height: 5), CustomTextFieldForexWrapper( - isFocused: false, + // isFocused: false, + isFocused: focusStates["hotel_nameFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: TextField( + focusNode: focusNodes["hotel_nameFocusNode"], controller: controllers["hotel_name"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( @@ -353,12 +376,13 @@ class HotelsDataState extends State { ), SizedBox(height: 5), CustomTextFieldForexWrapper( - isFocused: false, + isFocused: focusStates["hotel_chainFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: TextField( + focusNode: focusNodes["hotel_chainFocusNode"], controller: controllers["hotel_chain"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( @@ -394,12 +418,14 @@ class HotelsDataState extends State { ), SizedBox(height: 5), CustomTextFieldForexWrapper( - isFocused: false, + // isFocused: false, + isFocused: focusStates["categoryFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: TextField( + focusNode: focusNodes["categoryFocusNode"], controller: controllers["category"], inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 ]')), @@ -432,61 +458,102 @@ class HotelsDataState extends State { SizedBox(height: 5), CustomTextFieldForexWrapper( isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: widget.isDesktop, child: SizedBox( height: 40, - child: DropdownSearch( - selectedItem: countryMap[selectedCountry], - popupProps: PopupProps.menu( - showSearchBox: true, // Enables search functionality - menuProps: const MenuProps(backgroundColor: Colors.white), - constraints: BoxConstraints(maxHeight: 250), - itemBuilder: - (context, item, isSelected) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, + width: double.infinity, + child: Focus( + focusNode: focusNodes["country_codeFocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["country_codeFocused"] = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + focusNodes["country_codeFocusNode"]?.requestFocus(); + }, + child: DropdownSearch( + selectedItem: countryMap[selectedCountry], + popupProps: PopupProps.menu( + showSearchBox: true, // Enables search functionality + menuProps: const MenuProps(backgroundColor: Colors.white), + constraints: BoxConstraints(maxHeight: 200), + itemBuilder: + (context, item, isSelected) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 11.5), + ), + ), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search ...", + hintStyle: GoogleFonts.poppins(fontSize: 11), + contentPadding: EdgeInsets.symmetric(horizontal: 4), + ), + ), ), - child: Text( - item, - style: GoogleFonts.poppins(fontSize: 11.5), + items: countryMap.values.toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["country_codeFocused"] ?? false) + ? widget.layoutColor! + : Colors.white, + // width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["country_codeFocused"] ?? false) + ? widget.layoutColor! + : Colors.white, + // : const Color(0xFFD6D5E6), + // width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: widget.layoutColor!, width: 1), + ), + contentPadding: EdgeInsets.symmetric(horizontal: 10.0, + vertical: 8.0,), + ), ), + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + onChanged: (String? newValue) { + setState(() { + // Find the country_code based on selected country_name + selectedCountry = + countryMap.entries + .firstWhere((entry) => entry.value == newValue) + .key; + selectedCountryName = newValue; + }); + }, ), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search ...", - hintStyle: GoogleFonts.poppins(fontSize: 11), - contentPadding: EdgeInsets.symmetric(horizontal: 4), - ), - ), - ), - items: countryMap.values.toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select ", - style: GoogleFonts.poppins(fontSize: 11), - ), - ), - onChanged: (String? newValue) { - setState(() { - // Find the country_code based on selected country_name - selectedCountry = - countryMap.entries - .firstWhere((entry) => entry.value == newValue) - .key; - selectedCountryName = newValue; - }); - }, - ), + ) + ) ), ), if (errorMessages["country_code"] != null) ...[ @@ -512,12 +579,13 @@ class HotelsDataState extends State { ), SizedBox(height: 5), CustomTextFieldForexWrapper( - isFocused: false, + isFocused: focusStates["cityFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: TextField( + focusNode: focusNodes["cityFocusNode"], controller: controllers["city"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( diff --git a/lib/Screens/myTemplates/template.dart b/lib/Screens/myTemplates/template.dart index 5e0f4bd..b1eb202 100644 --- a/lib/Screens/myTemplates/template.dart +++ b/lib/Screens/myTemplates/template.dart @@ -33,6 +33,7 @@ import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; +import '../../widgets/custom_breadcrumb_navigation.dart'; import '../../widgets/custom_user_travel.dart'; import 'dialog_placeholders.dart'; @@ -60,6 +61,8 @@ class TemplateState extends State