diff --git a/lib/Screens/itnerary/flights.dart b/lib/Screens/itnerary/flights.dart index 360c8ed..0a98e7d 100644 --- a/lib/Screens/itnerary/flights.dart +++ b/lib/Screens/itnerary/flights.dart @@ -151,16 +151,16 @@ class FlightScreenState extends State { // Loop through each row and add listeners to clear errors for (int i = 1; i <= rowCount; i++) { textControllers["_from${i}Controller"]?.addListener( - () => _clearError("from_place_$i"), + () => _clearError("from_place_$i"), ); textControllers["_to${i}Controller"]?.addListener( - () => _clearError("to_place_$i"), + () => _clearError("to_place_$i"), ); textControllers["_date${i}Controller"]?.addListener( - () => _clearError("date_$i"), + () => _clearError("date_$i"), ); textControllers["_time${i}Controller"]?.addListener( - () => _clearError("time_$i"), + () => _clearError("time_$i"), ); } // loadCountryList(); @@ -184,13 +184,13 @@ class FlightScreenState extends State { } Map getFlightTripDateRange( - List> flightData, - ) { + List> flightData, + ) { final allTrips = - flightData - .expand((flight) => flight['trips'] ?? []) - .whereType>() - .toList(); + flightData + .expand((flight) => flight['trips'] ?? []) + .whereType>() + .toList(); if (allTrips.isEmpty) { return {'firstTripDate': null, 'lastTripDate': null}; @@ -304,11 +304,11 @@ class FlightScreenState extends State { // Determine the row count based on selectedTripType int rowCount = - selectedTripType == "Roundtrip" - ? 2 - : selectedTripType == "Multitrip" - ? multiTripRowCount - : 1; + selectedTripType == "Roundtrip" + ? 2 + : selectedTripType == "Multitrip" + ? multiTripRowCount + : 1; // Initialize fields dynamically for (var field in dataHeader) { @@ -681,13 +681,13 @@ class FlightScreenState extends State { // Same date - check time gap // Combine parsedDates and times into DateTime objects String prevDateStr = - textControllers["_date${i}Controller"]!.text.trim(); + textControllers["_date${i}Controller"]!.text.trim(); String prevTimeStr = - textControllers["_time${i}Controller"]!.text.trim(); + textControllers["_time${i}Controller"]!.text.trim(); String currDateStr = - textControllers["_date${i + 1}Controller"]!.text.trim(); + textControllers["_date${i + 1}Controller"]!.text.trim(); String currTimeStr = - textControllers["_time${i + 1}Controller"]!.text.trim(); + textControllers["_time${i + 1}Controller"]!.text.trim(); final dtFormat = DateFormat("dd-MM-yyyy HH:mm"); final prevDT = dtFormat.parse("$prevDateStr $prevTimeStr"); @@ -739,11 +739,11 @@ class FlightScreenState extends State { // updatedTextControllers["_from${newIndex}Controller"] = // textControllers["_from${i}Controller"]!; updatedTextControllers["_to${newIndex}Controller"] = - textControllers["_to${i}Controller"]!; + textControllers["_to${i}Controller"]!; updatedTextControllers["_date${newIndex}Controller"] = - textControllers["_date${i}Controller"]!; + textControllers["_date${i}Controller"]!; updatedTextControllers["_time${newIndex}Controller"] = - textControllers["_time${i}Controller"]!; + textControllers["_time${i}Controller"]!; newIndex++; } textControllers = updatedTextControllers; @@ -953,14 +953,14 @@ class FlightScreenState extends State { List purposeList = widget.apiData?['flight_trip_type'] ?? []; List> dropdownItems = - purposeList - .map( - (item) => DropdownMenuItem( - value: item['dropdown_value'], - child: Text(item['dropdown_value']), - ), - ) - .toList(); + purposeList + .map( + (item) => DropdownMenuItem( + value: item['dropdown_value'], + child: Text(item['dropdown_value']), + ), + ) + .toList(); if (dropdownItems.isEmpty) { dropdownItems.add( @@ -985,9 +985,9 @@ class FlightScreenState extends State { width: double.infinity, child: DropdownSearch( items: - purposeList - .map((item) => item['dropdown_value'] as String) - .toList(), + purposeList + .map((item) => item['dropdown_value'] as String) + .toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( border: InputBorder.none, @@ -1019,28 +1019,28 @@ class FlightScreenState extends State { selectedItem: selectedTripType, dropdownBuilder: (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: TextStyle(fontSize: 12), - ), - ), + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: TextStyle(fontSize: 12), + ), + ), 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 - ), - ), + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Text( + item, + style: TextStyle( + fontSize: 13, + ), // Custom text size for dropdown items + ), + ), ), ), @@ -1155,9 +1155,9 @@ class FlightScreenState extends State { ), SizedBox( width: - isDesktop - ? MediaQuery.of(context).size.width * 0.58 - : 80, // Ensure full width + isDesktop + ? MediaQuery.of(context).size.width * 0.58 + : 80, // Ensure full width child: Stack( alignment: Alignment.center, // Centers the icon children: [ @@ -1167,7 +1167,7 @@ class FlightScreenState extends State { color: Colors.white, // Background to avoid overlapping child: Row( mainAxisSize: - MainAxisSize.min, // Prevents row from taking full width + MainAxisSize.min, // Prevents row from taking full width children: [ Icon(Icons.add_circle_sharp, color: Colors.blue, size: 28), ], @@ -1224,14 +1224,14 @@ class FlightScreenState extends State { List purposeList = widget.apiDataForClass?['flight_class'] ?? []; List> dropdownItems = - purposeList - .map( - (item) => DropdownMenuItem( - value: item['dropdown_key'], - child: Text(item['dropdown_value']), - ), - ) - .toList(); + purposeList + .map( + (item) => DropdownMenuItem( + value: item['dropdown_key'], + child: Text(item['dropdown_value']), + ), + ) + .toList(); if (dropdownItems.isEmpty) { dropdownItems.add( @@ -1247,7 +1247,7 @@ class FlightScreenState extends State { // Default selected value selectedClasses[index] ??= - dropdownItems.isNotEmpty ? dropdownItems.first.value : null; + dropdownItems.isNotEmpty ? dropdownItems.first.value : null; // ------------------------------------------------- DateTime? _selectedCheckOutDate; @@ -1290,10 +1290,10 @@ class FlightScreenState extends State { } DateTime initialDate = - _selectedCheckOutDate != null && - _selectedCheckOutDate!.isAfter(firstDate) - ? _selectedCheckOutDate! - : firstDate; + _selectedCheckOutDate != null && + _selectedCheckOutDate!.isAfter(firstDate) + ? _selectedCheckOutDate! + : firstDate; DateTime? pickedDate = await showDatePicker( context: context, @@ -1315,10 +1315,10 @@ class FlightScreenState extends State { } Future _selectCheckOutTime( - BuildContext context, - int index, - VoidCallback onPicked, - ) async { + BuildContext context, + int index, + VoidCallback onPicked, + ) async { TimeOfDay? pickedTime = await showTimePicker( context: context, initialTime: _selectedCheckOutTime ?? TimeOfDay.now(), @@ -1344,8 +1344,8 @@ class FlightScreenState extends State { // ✅ Only validate past time if date is today final isToday = selectedDate.year == now.year && - selectedDate.month == now.month && - selectedDate.day == now.day; + selectedDate.month == now.month && + selectedDate.day == now.day; bool isPastTime = selectedDateTime.isBefore(now); @@ -1412,159 +1412,159 @@ class FlightScreenState extends State { child: SizedBox( height: 40, 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, - ), - ), - 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, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 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( - 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), - ), - ), - 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]!; - } - }); - }, + 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, ), + ), + 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, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 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( + 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), + ), + ), + 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]!; + } + }); + }, + ), ), // child: SizedBox( @@ -1612,156 +1612,156 @@ class FlightScreenState extends State { 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, - ), - ), - 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, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 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( - 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), - ), - ), - - // 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]!; - } - }); - }, + 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, ), + ), + 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, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 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( + 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), + ), + ), + + // 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]!; + } + }); + }, + ), ), ), if (errorMessages["to_place_$index"] != null) ...[ @@ -1848,7 +1848,7 @@ class FlightScreenState extends State { child: DropdownSearch>( items: purposeList.cast>(), selectedItem: purposeList.firstWhere( - (item) => item['dropdown_key'] == selectedClasses[index], + (item) => item['dropdown_key'] == selectedClasses[index], orElse: () => {}, ), itemAsString: (item) => item['dropdown_value'] ?? '', @@ -1900,14 +1900,14 @@ class FlightScreenState extends State { ); }, onChanged: - purposeList.isNotEmpty - ? (Map? newValue) { - setState(() { - selectedClasses[index] = newValue?['dropdown_key']; - print("Selected Class: ${selectedClasses[index]}"); - }); - } - : null, + purposeList.isNotEmpty + ? (Map? newValue) { + setState(() { + selectedClasses[index] = newValue?['dropdown_key']; + print("Selected Class: ${selectedClasses[index]}"); + }); + } + : null, ), ), ), @@ -2003,7 +2003,7 @@ class FlightScreenState extends State { _selectCheckOutTime(context, index, () { validateTimeDifference(index); setState( - () {}, + () {}, ); // ✅ Force rebuild to show the error immediately }); }, @@ -2060,17 +2060,17 @@ class FlightScreenState extends State { // Default selected value List> dropdownItems = - visa_available - .map( - (item) => DropdownMenuItem( - value: item['dropdown_key'], - child: Text(item['dropdown_value']), - ), - ) - .toList(); + visa_available + .map( + (item) => DropdownMenuItem( + value: item['dropdown_key'], + child: Text(item['dropdown_value']), + ), + ) + .toList(); selectedvisa_available ??= - dropdownItems.isNotEmpty ? dropdownItems.first.value : null; + dropdownItems.isNotEmpty ? dropdownItems.first.value : null; if (dropdownItems.isEmpty) { dropdownItems.add( @@ -2161,7 +2161,7 @@ class FlightScreenState extends State { child: DropdownSearch>( items: visa_available.cast>(), selectedItem: visa_available.firstWhere( - (item) => item['dropdown_key'] == selectedvisa_available, + (item) => item['dropdown_key'] == selectedvisa_available, orElse: () => {}, ), itemAsString: (item) => item['dropdown_value'] ?? '', @@ -2213,14 +2213,14 @@ class FlightScreenState extends State { ); }, onChanged: - visa_available.isNotEmpty - ? (Map? newValue) { - setState(() { - selectedvisa_available = newValue?['dropdown_key']; - print("Selected Visa: $selectedvisa_available"); - }); - } - : null, + visa_available.isNotEmpty + ? (Map? newValue) { + setState(() { + selectedvisa_available = newValue?['dropdown_key']; + print("Selected Visa: $selectedvisa_available"); + }); + } + : null, ), ), ), @@ -2281,17 +2281,17 @@ class FlightScreenState extends State { // Default selected value List> dropdownItems = - visa_available - .map( - (item) => DropdownMenuItem( - value: item['dropdown_key'], - child: Text(item['dropdown_value']), - ), - ) - .toList(); + visa_available + .map( + (item) => DropdownMenuItem( + value: item['dropdown_key'], + child: Text(item['dropdown_value']), + ), + ) + .toList(); selectedvisa_available ??= - dropdownItems.isNotEmpty ? dropdownItems.first.value : null; + dropdownItems.isNotEmpty ? dropdownItems.first.value : null; if (dropdownItems.isEmpty) { dropdownItems.add( @@ -2340,20 +2340,20 @@ class FlightScreenState extends State { ), // Proper padding ), onChanged: - visa_available.isNotEmpty - ? (newValue) { - setState(() { - selectedvisa_available = newValue; - // selectedTripType = "Oneway"; - // Reset `multiTripRowCount` when switching away from Multitrip - }); - print( - "Updating form data: Flight -> trip_type -> $selectedvisa_available", - ); + visa_available.isNotEmpty + ? (newValue) { + setState(() { + selectedvisa_available = newValue; + // selectedTripType = "Oneway"; + // Reset `multiTripRowCount` when switching away from Multitrip + }); + print( + "Updating form data: Flight -> trip_type -> $selectedvisa_available", + ); - // _initializeRows(); - } - : null, + // _initializeRows(); + } + : null, items: dropdownItems, ), diff --git a/lib/Screens/itnerary/forex.dart b/lib/Screens/itnerary/forex.dart index a7afcf9..611a049 100644 --- a/lib/Screens/itnerary/forex.dart +++ b/lib/Screens/itnerary/forex.dart @@ -1096,8 +1096,9 @@ class _ForexScreenState extends State { SizedBox(height: 5), // Space before error message Text( errorMessages["end_date"]!, - // "Select End Date", - style: TextStyle(color: Colors.red, fontSize: 12), + style: const TextStyle(color: Colors.red, fontSize: 12), + maxLines: 2, // Allow it to wrap onto two lines + overflow: TextOverflow.ellipsis, // Add ellipsis if it still overflows ), ], ], diff --git a/lib/Screens/itnerary/insurance.dart b/lib/Screens/itnerary/insurance.dart index ea10881..98de2a1 100644 --- a/lib/Screens/itnerary/insurance.dart +++ b/lib/Screens/itnerary/insurance.dart @@ -38,20 +38,21 @@ class _InsuranceScreenState extends State { final FocusNode _tripTypeFocusNode = FocusNode(); final FocusNode _hotelNameFocusNode = FocusNode(); - final FocusNode _fromFocusNode = FocusNode(); - final FocusNode _dateFocusNode = FocusNode(); + final FocusNode _startDateFocusNode = FocusNode(); + final FocusNode _endDateFocusNode = FocusNode(); final FocusNode _commentsFocusNode = FocusNode(); final FocusNode _nomineeFocusNode = FocusNode(); late TextEditingController _tripTypeController = TextEditingController(); - late TextEditingController _startdateController = TextEditingController(); + late TextEditingController _startDateController = TextEditingController(); late TextEditingController _endDateController = TextEditingController(); late TextEditingController _insuranceCommentsController = TextEditingController(); late TextEditingController _nomineeController = TextEditingController(); bool _isHotelNameFocused = false; - bool _dateFocus = false; + bool _startDateFocus = false; + bool _endDateFocus = false; bool _commentsFocus = false; bool _nomineeFocus = false; @@ -63,7 +64,7 @@ class _InsuranceScreenState extends State { Map get InsuranceData { Map data = { "type_of_insurance": selectedInsuranceType, - "start_date": _startdateController.text, + "start_date": _startDateController.text, "end_date": _endDateController.text, "comments": _insuranceCommentsController.text, "nominee_name": _nomineeController.text, @@ -93,9 +94,14 @@ class _InsuranceScreenState extends State { _isHotelNameFocused = _hotelNameFocusNode.hasFocus; }); }); - _dateFocusNode.addListener(() { + _endDateFocusNode.addListener(() { setState(() { - _dateFocus = _fromFocusNode.hasFocus; + _endDateFocus = _endDateFocusNode.hasFocus; + }); + }); + _startDateFocusNode.addListener(() { + setState(() { + _startDateFocus = _startDateFocusNode.hasFocus; }); }); _commentsFocusNode.addListener(() { @@ -113,7 +119,7 @@ class _InsuranceScreenState extends State { _insuranceCommentsController = TextEditingController( text: widget.selectedItem?["comments"] ?? "", ); - _startdateController = TextEditingController( + _startDateController = TextEditingController( text: widget.selectedItem?["start_date"] ?? "", ); _endDateController = TextEditingController( @@ -141,26 +147,15 @@ class _InsuranceScreenState extends State { // ✅ Only set controller after value is updated // final parsedDate = // DateTime.tryParse(flightFirstTripDateNotifier.value ?? ''); - final parsedDate = DateFormat( - "dd-MM-yyyy", - ).parse(flightFirstTripDateNotifier.value ?? ''); - if (parsedDate != null) { - _startdateController.text = DateFormat('dd-MM-yyyy').format(parsedDate); - } + final parsedDate = DateFormat("dd-MM-yyyy").parse(flightFirstTripDateNotifier.value ?? ''); + if (parsedDate != null) { _startDateController.text = DateFormat('dd-MM-yyyy').format(parsedDate); } - final parsedEndDate = DateFormat( - "dd-MM-yyyy", - ).parse(flightLastTripDateNotifier.value ?? ''); - if (parsedEndDate != null) { - _endDateController.text = DateFormat( - 'dd-MM-yyyy', - ).format(parsedEndDate); + final parsedEndDate = DateFormat("dd-MM-yyyy").parse(flightLastTripDateNotifier.value ?? ''); + if (parsedEndDate != null) { _endDateController.text = DateFormat('dd-MM-yyyy').format(parsedEndDate); } + + print("parsedDate $parsedDate"); + print("parsedEndDate $parsedEndDate"); - print("parsedDate"); - print(parsedDate); - print("parsedEndDate"); - print(parsedEndDate); - } }); } @@ -267,7 +262,8 @@ class _InsuranceScreenState extends State { void dispose() { _tripTypeFocusNode.dispose(); _tripTypeController.dispose(); - _startdateController.dispose(); + _startDateController.dispose(); + _endDateController.dispose(); _insuranceCommentsController.dispose(); _nomineeController.dispose(); super.dispose(); @@ -592,105 +588,23 @@ class _InsuranceScreenState extends State { if (pickedDate != null && pickedDate != _selectedCheckOutDate) { setState(() { _selectedCheckOutDate = pickedDate; - _startdateController.text = DateFormat( + _startDateController.text = DateFormat( 'dd-MM-yyyy', ).format(pickedDate); }); } } - // Future _selectEndCheckOutDate(BuildContext context) async { - // DateTime now = DateTime.now(); - // DateTime today = DateTime(now.year, now.month, now.day); - // - // // DateTime? checkInDate; - // // try { - // // checkInDate = DateTime.parse(_startdateController.text); - // // } catch (e) { - // // checkInDate = today; - // // } - // - // // // Ensure at least today is used - // // DateTime firstDate = checkInDate.isAfter(today) ? checkInDate : today; - // // DateTime initialDate = _selectedCheckOutDate != null && - // // _selectedCheckOutDate!.isAfter(firstDate) - // // ? _selectedCheckOutDate! - // // : firstDate; - // - // // DateTime firstDate = checkInDate; - // // DateTime initialDate = - // // _selectedCheckOutDate != null && - // // _selectedCheckOutDate!.isAfter(firstDate) - // // ? _selectedCheckOutDate! - // // : firstDate; - // - // DateTime? validFromDate; - // - // try { - // String fromDateText = _startdateController.text.trim(); - // print("Valid From Text: $fromDateText"); - // if (fromDateText.isNotEmpty) { - // validFromDate = DateFormat('dd-MM-yyyy').parseStrict(fromDateText); - // print("Parsed Valid From: $validFromDate"); - // } - // } catch (e) { - // print("Error parsing valid from date: $e"); - // } - // - // // Use max(today, validFromDate) as firstDate - // // DateTime firstDate = today; - // DateTime firstDate = validFromDate ?? today; - // if (validFromDate != null && validFromDate.isAfter(today)) { - // firstDate = validFromDate; - // } - // final pickedDate = await showDatePicker( - // context: context, - // // initialDate: initialDate, - // // firstDate: initialDate, - // // firstDate: DateTime(1900), - // initialDate: firstDate, - // firstDate: firstDate, - // lastDate: DateTime(2100), - // initialEntryMode: DatePickerEntryMode.calendarOnly, - // ); - // - // // final pickedDate = await showDatePicker( - // // context: context, - // // // initialDate: initialDate, - // // initialDate: initialDate, - // // firstDate: initialDate, - // // lastDate: DateTime(2100), - // // initialEntryMode: DatePickerEntryMode.calendarOnly, - // // ); - // - // // DateTime? pickedDate = await showDatePicker( - // // context: context, - // // initialDate: _selectedCheckOutDate != null && - // // _selectedCheckOutDate!.isAfter(today) - // // ? _selectedCheckOutDate! - // // : today, - // // firstDate: today, - // // lastDate: DateTime(2100), - // // ); - // - // if (pickedDate != null && pickedDate != _selectedCheckOutDate) { - // setState(() { - // _selectedCheckOutDate = pickedDate; - // _endDateController.text = DateFormat('dd-MM-yyyy').format(pickedDate); - // }); - // } - // } - Future _selectEndCheckOutDate(BuildContext context) async { DateTime now = DateTime.now(); DateTime today = DateTime(now.year, now.month, now.day); - DateTime? checkInDate; - try { - checkInDate = DateTime.parse(_startdateController.text); - } catch (e) { - checkInDate = today; - } + // DateTime? checkInDate; + // try { + // checkInDate = DateTime.parse(_startDateController.text); + // } catch (e) { + // checkInDate = today; + // } // // Ensure at least today is used // DateTime firstDate = checkInDate.isAfter(today) ? checkInDate : today; @@ -699,20 +613,52 @@ class _InsuranceScreenState extends State { // ? _selectedCheckOutDate! // : firstDate; - DateTime firstDate = checkInDate; - DateTime initialDate = - _selectedCheckOutDate != null && - _selectedCheckOutDate!.isAfter(firstDate) - ? _selectedCheckOutDate! - : firstDate; + // DateTime firstDate = checkInDate; + // DateTime initialDate = + // _selectedCheckOutDate != null && + // _selectedCheckOutDate!.isAfter(firstDate) + // ? _selectedCheckOutDate! + // : firstDate; + DateTime? validFromDate; + + try { + String fromDateText = _startDateController.text.trim(); + print("Valid From Text: $fromDateText"); + if (fromDateText.isNotEmpty) { + validFromDate = DateFormat('dd-MM-yyyy').parseStrict(fromDateText); + print("Parsed Valid From: $validFromDate"); + } + } catch (e) { + print("Error parsing valid from date: $e"); + } + + // Use max(today, validFromDate) as firstDate + // DateTime firstDate = today; + DateTime firstDate = validFromDate ?? today; + if (validFromDate != null && validFromDate.isAfter(today)) { + firstDate = validFromDate; + } final pickedDate = await showDatePicker( context: context, - initialDate: initialDate, + // initialDate: initialDate, + // firstDate: initialDate, + // firstDate: DateTime(1900), + initialDate: firstDate, firstDate: firstDate, lastDate: DateTime(2100), + initialEntryMode: DatePickerEntryMode.calendarOnly, ); + // final pickedDate = await showDatePicker( + // context: context, + // // initialDate: initialDate, + // initialDate: initialDate, + // firstDate: initialDate, + // lastDate: DateTime(2100), + // initialEntryMode: DatePickerEntryMode.calendarOnly, + // ); + // DateTime? pickedDate = await showDatePicker( // context: context, // initialDate: _selectedCheckOutDate != null && @@ -806,7 +752,7 @@ class _InsuranceScreenState extends State { child: DropdownSearch>( items: purposeList.cast>(), selectedItem: purposeList.firstWhere( - (item) => item['dropdown_key'] == selectedInsuranceType, + (item) => item['dropdown_key'] == selectedInsuranceType, orElse: () => {}, ), itemAsString: (item) => item['dropdown_value'] ?? '', @@ -833,10 +779,7 @@ class _InsuranceScreenState extends State { dropdownDecoratorProps: const DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 10, - ), + contentPadding: EdgeInsets.symmetric(horizontal: 10,vertical: 10,), ), ), dropdownBuilder: (context, selectedItem) { @@ -858,19 +801,18 @@ class _InsuranceScreenState extends State { ); }, onChanged: - purposeList.isNotEmpty - ? (Map? newValue) { - setState(() { - selectedInsuranceType = newValue?['dropdown_key']; - print( - "selected Insurance Type: ${selectedInsuranceType}", - ); - }); - } - : null, + purposeList.isNotEmpty + ? (Map? newValue) { + setState(() { + selectedInsuranceType= newValue?['dropdown_key']; + print("selected Insurance Type: ${selectedInsuranceType}"); + }); + } + : null, ), ), ), + ], ), @@ -925,7 +867,7 @@ class _InsuranceScreenState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _dateFocus, + isFocused: _startDateFocus, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, child: SizedBox( @@ -933,7 +875,7 @@ class _InsuranceScreenState extends State { child: GestureDetector( onTap: () async { await _selectCheckOutDate(context); - if (_startdateController.text.isNotEmpty) { + if (_startDateController.text.isNotEmpty) { setState(() { errorMessages.remove( "start_date", @@ -943,8 +885,8 @@ class _InsuranceScreenState extends State { }, child: AbsorbPointer( child: TextField( - focusNode: _dateFocusNode, - controller: _startdateController, + focusNode: _startDateFocusNode, + controller: _startDateController, style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select ", @@ -983,7 +925,7 @@ class _InsuranceScreenState extends State { ), SizedBox(height: 5), CustomTextFieldWrapper( - isFocused: _dateFocus, + isFocused: _endDateFocus, isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, child: SizedBox( @@ -993,7 +935,7 @@ class _InsuranceScreenState extends State { await _selectEndCheckOutDate(context); if (_endDateController.text.isNotEmpty) { - DateTime? startDate = _parseDate(_startdateController.text); + DateTime? startDate = _parseDate(_startDateController.text); DateTime? endDate = _parseDate(_endDateController.text); if (startDate != null && @@ -1012,7 +954,7 @@ class _InsuranceScreenState extends State { }, child: AbsorbPointer( child: TextField( - focusNode: _dateFocusNode, + focusNode: _endDateFocusNode, controller: _endDateController, style: const TextStyle(fontSize: 12), decoration: const InputDecoration( @@ -1035,9 +977,10 @@ class _InsuranceScreenState extends State { if (errorMessages["end_date"] != null) ...[ SizedBox(height: 5), // Space before error message Text( - // "Required", errorMessages["end_date"]!, - style: TextStyle(color: Colors.red, fontSize: 12), + style: const TextStyle(color: Colors.red, fontSize: 12), + maxLines: 2, // Allow it to wrap onto two lines + overflow: TextOverflow.ellipsis, // Add ellipsis if it still overflows ), ], ], diff --git a/lib/Screens/itnerary_list/visa_list.dart b/lib/Screens/itnerary_list/visa_list.dart index 9429a8e..3f70b4a 100644 --- a/lib/Screens/itnerary_list/visa_list.dart +++ b/lib/Screens/itnerary_list/visa_list.dart @@ -334,7 +334,7 @@ class VisaListWidget extends StatelessWidget { Expanded( flex: 2, child: Text( - " Visa Type", + " Country", style: GoogleFonts.poppins( fontSize: 11, ), @@ -342,7 +342,7 @@ class VisaListWidget extends StatelessWidget { Expanded( flex: 2, child: Text( - " Country", + " Visa Type", style: GoogleFonts.poppins( fontSize: 11, ), @@ -372,8 +372,8 @@ class VisaListWidget extends StatelessWidget { Expanded( flex: 2, child: Text( - getRequestForVisa( - item["type_of_visa"]!.toString()), + getRequestForCountry( + item["country_code"]!.toString()), style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, @@ -384,8 +384,8 @@ class VisaListWidget extends StatelessWidget { Expanded( flex: 2, child: Text( - getRequestForCountry( - item["country_code"]!.toString()), + getRequestForVisa( + item["type_of_visa"]!.toString()), style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, diff --git a/lib/Screens/userManagement/create_user/create_user.dart b/lib/Screens/userManagement/create_user/create_user.dart index f2cf52e..da6bfb4 100644 --- a/lib/Screens/userManagement/create_user/create_user.dart +++ b/lib/Screens/userManagement/create_user/create_user.dart @@ -42,9 +42,9 @@ class _CreateUserFormDetialsState extends State { final ApiService apiService = ApiService(); final GlobalKey personalDetailsKey = - GlobalKey(); + GlobalKey(); final GlobalKey travellerDetailsKey = - GlobalKey(); + GlobalKey(); // late List?> travelDetailsData; Map? travelDetailsData; @@ -299,7 +299,7 @@ class _CreateUserFormDetialsState extends State { // Fix the invalid JSON (dangerous if the format changes) final fixedJson = raw.replaceAllMapped( RegExp(r'(\w+):'), // matches `service_id:` - (match) => '"${match.group(1)}":', + (match) => '"${match.group(1)}":', ); List decodedList = jsonDecode(fixedJson); @@ -363,7 +363,7 @@ class _CreateUserFormDetialsState extends State { // } final extraData = - GoRouterState.of(context).extra as Map?; + GoRouterState.of(context).extra as Map?; if (extraData != null) { print("extraData: ${extraData['selectedUser']}"); @@ -381,8 +381,8 @@ class _CreateUserFormDetialsState extends State { // Handle selectedUser as a Map (not a List) apiselectedUser = - extraData['selectedUser'] - as Map?; // Cast it as a Map + extraData['selectedUser'] + as Map?; // Cast it as a Map isViewMode = extraData['isViewMode'] ?? false; isEditProfile = extraData['isEditProfile'] ?? false; }); @@ -444,7 +444,7 @@ class _CreateUserFormDetialsState extends State { userMap = { for (var user in userList) user['user_id'].toString(): - "${user['first_name']} ${user['last_name']}", + "${user['first_name']} ${user['last_name']}", }; userIdsApi = userMap.keys.toList(); }); @@ -483,14 +483,14 @@ class _CreateUserFormDetialsState extends State { setState(() { layoutColor = - layoutString != null - ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; bodyColor = - bodyStringColor != null - ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); } @@ -700,6 +700,47 @@ class _CreateUserFormDetialsState extends State { print("USERDETAILS : $data"); + // block-submit-here + + // Additional validation starts - travelDetailsData passport + DateTime? start_Date = travelDetailsData?['date_of_issue']; + DateTime? end_Date = travelDetailsData?['date_of_expiry']; + + if (start_Date != null && end_Date != null && start_Date.toString().isNotEmpty && end_Date.toString().isNotEmpty) { + try { + final format = DateFormat("dd-MM-yyyy"); + final checkStartDate = format.parse("$start_Date"); + final checkEndDate = format.parse("$end_Date"); + + if (checkEndDate.isBefore(checkStartDate)) { + // return "End date cannot be earlier than start date";; + return ; + } + } catch (e) { // return "End date cannot be earlier than start date"; + return ; + // errorMessages["end_date"] = "Invalid date format"; + } + } + // valid_from: 20-06-2025, valid_upto: 19-06-2025 + DateTime? valid_from = data?['valid_from']; + DateTime? valid_upto = data?['valid_upto']; + + if (valid_from != null && valid_upto != null && valid_from.toString().isNotEmpty && valid_upto.toString().isNotEmpty) { + try { + final format = DateFormat("dd-MM-yyyy"); + final checkValidFrom = format.parse("$valid_from"); + final checkValidUpto = format.parse("$valid_upto"); + + if (checkValidUpto.isBefore(checkValidFrom)) { + // return "valid upto cannot be earlier than valid from"; + return ; + } + } catch (e) { // return "valid upto cannot be earlier than valid from"; + return ; + // errorMessages["end_date"] = "Invalid date format"; + } + } + // Map data = userDetials; if (!isValidData(data) && isValidDataTwo(data)) { @@ -744,7 +785,7 @@ class _CreateUserFormDetialsState extends State { if (data["mobile_no"] != null && data["mobile_no"].toString().isNotEmpty) { if (!RegExp(r"^\d{10}$").hasMatch(data["mobile_no"].toString())) { errorMessages["mobile_no"] = - "Enter 10 digits"; // Invalid mobile number format + "Enter 10 digits"; // Invalid mobile number format } } @@ -754,7 +795,7 @@ class _CreateUserFormDetialsState extends State { r"^\d{10}$", ).hasMatch(data["alternate_mobile_no"].toString())) { errorMessages["alternate_mobile_no"] = - "Enter 10 digits"; // Invalid mobile number format + "Enter 10 digits"; // Invalid mobile number format } } @@ -944,7 +985,7 @@ class _CreateUserFormDetialsState extends State { // ✅ Ensure UI updates if (isMatch) { errorMessages["password"] = - "New password is not similar to old password"; + "New password is not similar to old password"; print(" Password match!"); } else { print(" Password NOT match!"); @@ -973,16 +1014,16 @@ class _CreateUserFormDetialsState extends State { drawer: CustomDrawer(isDesktop: false), body: Padding( padding: - isDesktop - ? EdgeInsets.symmetric( - horizontal: - MediaQuery.of(context).size.width * - 0.1, // 30% of screen width as horizontal padding - vertical: - MediaQuery.of(context).size.height * - 0, // 5% of screen height as vertical padding - ) - : EdgeInsets.all(0), + isDesktop + ? EdgeInsets.symmetric( + horizontal: + MediaQuery.of(context).size.width * + 0.1, // 30% of screen width as horizontal padding + vertical: + MediaQuery.of(context).size.height * + 0, // 5% of screen height as vertical padding + ) + : EdgeInsets.all(0), child: Row( children: [Expanded(child: buildData(isDesktop, context))], ), @@ -1004,9 +1045,9 @@ class _CreateUserFormDetialsState extends State { Expanded( child: Container( height: - isDesktop - ? MediaQuery.of(context).size.height * 0.98 - : MediaQuery.of(context).size.height, + isDesktop + ? MediaQuery.of(context).size.height * 0.98 + : MediaQuery.of(context).size.height, child: Padding( padding: EdgeInsets.all(0.0), child: _buildUserDetails(isDesktop), @@ -1018,39 +1059,39 @@ class _CreateUserFormDetialsState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: - isDesktop - ? Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (selectedTab != "personal") - ..._buildBack(isDesktop, layoutColor!), - Spacer(), // spacing between buttons - // Next or Submit based on role or user type - if (selectedTab == "travel" || - selectedRole == "5" || - setSelectesUserType == true) - ..._buildSubmit(isDesktop, layoutColor!) - else - ..._buildNext(isDesktop, layoutColor!), - // (selectedTab == "travel" || - // selectedRole == "5" || - // setSelectesUserType == true) - // ? _buildSubmit(isDesktop, layoutColor!) - // : _buildNext( - // isDesktop, - // layoutColor!, - // ), // _buildGoBack(isDesktop, layoutColor!), - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.end, - children: - (selectedTab == "travel" || - selectedRole == "5" || - setSelectesUserType == true) - ? _buildSubmit(isDesktop, layoutColor!) - : _buildNext(isDesktop, layoutColor!), - ), + isDesktop + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (selectedTab != "personal") + ..._buildBack(isDesktop, layoutColor!), + Spacer(), // spacing between buttons + // Next or Submit based on role or user type + if (selectedTab == "travel" || + selectedRole == "5" || + setSelectesUserType == true) + ..._buildSubmit(isDesktop, layoutColor!) + else + ..._buildNext(isDesktop, layoutColor!), + // (selectedTab == "travel" || + // selectedRole == "5" || + // setSelectesUserType == true) + // ? _buildSubmit(isDesktop, layoutColor!) + // : _buildNext( + // isDesktop, + // layoutColor!, + // ), // _buildGoBack(isDesktop, layoutColor!), + ], + ) + : Row( + mainAxisAlignment: MainAxisAlignment.end, + children: + (selectedTab == "travel" || + selectedRole == "5" || + setSelectesUserType == true) + ? _buildSubmit(isDesktop, layoutColor!) + : _buildNext(isDesktop, layoutColor!), + ), ), ), ], @@ -1095,9 +1136,9 @@ class _CreateUserFormDetialsState extends State { isDesktop ? buildTabsForUser() : SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: buildTabsForUser(), - ), + scrollDirection: Axis.horizontal, + child: buildTabsForUser(), + ), Container( // color: Colors.yellow.shade50, height: MediaQuery.of(context).size.height * 0.64, @@ -1200,8 +1241,8 @@ class _CreateUserFormDetialsState extends State { ); case "travel": final fullName = - "${controllers["Fname"]?.text ?? ""} ${controllers["Lname"]?.text ?? ""}" - .trim(); + "${controllers["Fname"]?.text ?? ""} ${controllers["Lname"]?.text ?? ""}" + .trim(); return TravellerDetails( key: travellerDetailsKey, isDesktop: isDesktop, @@ -1260,69 +1301,69 @@ class _CreateUserFormDetialsState extends State { return Row( crossAxisAlignment: CrossAxisAlignment.end, // important children: - tabs.entries.map((entry) { - final targetTab = entry.key; + tabs.entries.map((entry) { + final targetTab = entry.key; - print("TargetsTAb: $targetTab"); + print("TargetsTAb: $targetTab"); - final isSelected = selectedTab == entry.key; - print("isSelected: $isSelected"); + final isSelected = selectedTab == entry.key; + print("isSelected: $isSelected"); - return GestureDetector( - onTap: () { - setState(() { - bool isValid = false; + return GestureDetector( + onTap: () { + setState(() { + bool isValid = false; - final currentTab = selectedTab; - if (currentTab == "personal") { - isValid = isValidData(userDetials); + final currentTab = selectedTab; + if (currentTab == "personal") { + isValid = isValidData(userDetials); - if (isValid) { - selectedTab = entry.key; - } - } else if (currentTab == "office" && - targetTab == "personal") { - selectedTab = entry.key; - } else if (currentTab == "office") { - isValid = isValidDataTwo(userDetials); - if (isValid) { - selectedTab = entry.key; - } - } else { - isValid = - true; // Travel tab might not need validation at this point - selectedTab = entry.key; - } - }); - }, - child: Padding( - padding: const EdgeInsets.only( - right: 24.0, - ), // space between tabs - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - entry.value, - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: - isSelected ? Color(0xFF114D8B) : Color(0xFF475569), - ), - ), - const SizedBox(height: 8), - AnimatedContainer( - duration: Duration(milliseconds: 300), - height: 2, - width: isSelected ? 50 : 0, // small line - color: Color(0xFF114D8B), - ), - ], + if (isValid) { + selectedTab = entry.key; + } + } else if (currentTab == "office" && + targetTab == "personal") { + selectedTab = entry.key; + } else if (currentTab == "office") { + isValid = isValidDataTwo(userDetials); + if (isValid) { + selectedTab = entry.key; + } + } else { + isValid = + true; // Travel tab might not need validation at this point + selectedTab = entry.key; + } + }); + }, + child: Padding( + padding: const EdgeInsets.only( + right: 24.0, + ), // space between tabs + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + entry.value, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: + isSelected ? Color(0xFF114D8B) : Color(0xFF475569), + ), ), - ), - ); - }).toList(), + const SizedBox(height: 8), + AnimatedContainer( + duration: Duration(milliseconds: 300), + height: 2, + width: isSelected ? 50 : 0, // small line + color: Color(0xFF114D8B), + ), + ], + ), + ), + ); + }).toList(), ); } @@ -1332,17 +1373,17 @@ class _CreateUserFormDetialsState extends State { return [ MouseRegion( cursor: - isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: - isViewMode ? layoutColor : layoutColor, // Keep original color + isViewMode ? layoutColor : layoutColor, // Keep original color foregroundColor: - isViewMode ? Colors.white : Colors.white, // Keep original color + isViewMode ? Colors.white : Colors.white, // Keep original color disabledBackgroundColor: - layoutColor, // Ensure color remains when disabled + layoutColor, // Ensure color remains when disabled disabledForegroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -1361,17 +1402,17 @@ class _CreateUserFormDetialsState extends State { return [ MouseRegion( cursor: - isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: - isViewMode ? layoutColor : layoutColor, // Keep original color + isViewMode ? layoutColor : layoutColor, // Keep original color foregroundColor: - isViewMode ? Colors.white : Colors.white, // Keep original color + isViewMode ? Colors.white : Colors.white, // Keep original color disabledBackgroundColor: - layoutColor, // Ensure color remains when disabled + layoutColor, // Ensure color remains when disabled disabledForegroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -1392,17 +1433,17 @@ class _CreateUserFormDetialsState extends State { return [ MouseRegion( cursor: - isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: TextButton( style: ElevatedButton.styleFrom( backgroundColor: - isViewMode ? Colors.white : Colors.white, // Keep original color + isViewMode ? Colors.white : Colors.white, // Keep original color foregroundColor: - isViewMode ? layoutColor : layoutColor, // Keep original color + isViewMode ? layoutColor : layoutColor, // Keep original color disabledBackgroundColor: - layoutColor, // Ensure color remains when disabled + layoutColor, // Ensure color remains when disabled disabledForegroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -1440,19 +1481,19 @@ class _CreateUserFormDetialsState extends State { if (!isViewMode) MouseRegion( cursor: - isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: - isViewMode ? layoutColor : layoutColor, // Keep original color + isViewMode ? layoutColor : layoutColor, // Keep original color foregroundColor: - isViewMode - ? Colors.white - : Colors.white, // Keep original color + isViewMode + ? Colors.white + : Colors.white, // Keep original color disabledBackgroundColor: - layoutColor, // Ensure color remains when disabled + layoutColor, // Ensure color remains when disabled disabledForegroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -1461,7 +1502,7 @@ class _CreateUserFormDetialsState extends State { padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: - isViewMode ? null : handleSubmit, // Disable when in view mode + isViewMode ? null : handleSubmit, // Disable when in view mode child: Text("Submit"), ), ), diff --git a/lib/Screens/userManagement/create_user/office_details.dart b/lib/Screens/userManagement/create_user/office_details.dart index cd69508..a015f23 100644 --- a/lib/Screens/userManagement/create_user/office_details.dart +++ b/lib/Screens/userManagement/create_user/office_details.dart @@ -692,6 +692,9 @@ class _OfficeDetailsState extends State { enabled: !widget.isViewMode, popupProps: PopupProps.menu( + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), showSearchBox: true, fit: FlexFit.loose, // Allows flexible height itemBuilder: diff --git a/lib/Screens/userManagement/create_user/traveller_details.dart b/lib/Screens/userManagement/create_user/traveller_details.dart index 3819349..3781bce 100644 --- a/lib/Screens/userManagement/create_user/traveller_details.dart +++ b/lib/Screens/userManagement/create_user/traveller_details.dart @@ -1584,7 +1584,9 @@ class TravellerDetailsState extends State { SizedBox(height: 5), // Space before error message Text( errorMessages["date_of_expiry"]!, - style: TextStyle(color: Colors.red, fontSize: 12), + style: const TextStyle(color: Colors.red, fontSize: 10), + maxLines: 2, // Allow it to wrap onto two lines + overflow: TextOverflow.ellipsis, // Add ellipsis if it still overflows ), ], ], @@ -4085,7 +4087,7 @@ class TravellerDetailsState extends State { // Revalidate expiry if (_selectedCheckOutDate != null && _selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) { - errorMessages["valid_upto"] = "end date cannot be earlier than from date"; + errorMessages["valid_upto"] = "valid upto cannot be earlier than valid from"; } else { errorMessages.remove("valid_upto"); } @@ -4201,7 +4203,7 @@ class TravellerDetailsState extends State { if (_selectedCheckInDate != null && _selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) { - errorMessages["valid_upto"] = "end date cannot be earlier than from date"; + errorMessages["valid_upto"] = "valid upto cannot be earlier than valid from"; } else { errorMessages.remove("valid_upto"); } @@ -4257,6 +4259,15 @@ class TravellerDetailsState extends State { ), ), ), + if (errorMessages["valid_upto"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["valid_upto"]!, + style: const TextStyle(color: Colors.red, fontSize: 10), + maxLines: 2, // Allow it to wrap onto two lines + overflow: TextOverflow.ellipsis, // Add ellipsis if it still overflows + ), + ], ], ); }