ui changes
This commit is contained in:
parent
5c628282c6
commit
36975e716f
@ -9,8 +9,11 @@ import '../../widgets/custom_text_field.dart';
|
|||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class FlightScreen extends StatefulWidget {
|
class FlightScreen extends StatefulWidget {
|
||||||
|
final bool hasAction;
|
||||||
|
final String? tripType;
|
||||||
final List<Map<String, dynamic>> flightData;
|
final List<Map<String, dynamic>> flightData;
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
|
final Map<String, dynamic>? apiDataForClass;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Function(Map<String, dynamic>) onSaveFlight;
|
final Function(Map<String, dynamic>) onSaveFlight;
|
||||||
@ -22,7 +25,10 @@ class FlightScreen extends StatefulWidget {
|
|||||||
required this.onClose,
|
required this.onClose,
|
||||||
required this.onSaveFlight,
|
required this.onSaveFlight,
|
||||||
required this.selectedItem,
|
required this.selectedItem,
|
||||||
required this.flightData});
|
required this.flightData,
|
||||||
|
required this.hasAction,
|
||||||
|
this.tripType,
|
||||||
|
this.apiDataForClass});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_FlightScreenState createState() => _FlightScreenState();
|
_FlightScreenState createState() => _FlightScreenState();
|
||||||
@ -32,6 +38,10 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
ApiService apiService = ApiService();
|
ApiService apiService = ApiService();
|
||||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
bool isCountryLoading = true;
|
||||||
|
late Map<String, String> countryMap;
|
||||||
|
late List<String> countryCodes;
|
||||||
|
|
||||||
late ValueNotifier<String?> flightFirstTripDateNotifier;
|
late ValueNotifier<String?> flightFirstTripDateNotifier;
|
||||||
late ValueNotifier<String?> flightLastTripDateNotifier;
|
late ValueNotifier<String?> flightLastTripDateNotifier;
|
||||||
|
|
||||||
@ -42,6 +52,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
String? selectedTripType;
|
String? selectedTripType;
|
||||||
Map<int, String?> selectedClasses = {}; // Store class selection for each trip
|
Map<int, String?> selectedClasses = {}; // Store class selection for each trip
|
||||||
|
Map<int, String?> selectedFrom = {}; // Store class selection for each trip
|
||||||
|
Map<int, String?> selectedTo = {}; // Store class selection for each trip
|
||||||
String? selectedvisa_available;
|
String? selectedvisa_available;
|
||||||
int multiTripRowCount = 1;
|
int multiTripRowCount = 1;
|
||||||
|
|
||||||
@ -66,7 +78,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
List<TextEditingController> controllers = []; // Dynamic controllers
|
List<TextEditingController> controllers = []; // Dynamic controllers
|
||||||
|
|
||||||
Map<String, String> errorMessages = {};
|
Map<String, String> errorMessages = {};
|
||||||
|
// forex_pre_paid_card_number
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -120,7 +132,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
textControllers["_time${i}Controller"]
|
textControllers["_time${i}Controller"]
|
||||||
?.addListener(() => _clearError("time_$i"));
|
?.addListener(() => _clearError("time_$i"));
|
||||||
}
|
}
|
||||||
// loadCountryList();
|
loadCountryList();
|
||||||
|
|
||||||
flightFirstTripDateNotifier = ValueNotifier<String?>(null);
|
flightFirstTripDateNotifier = ValueNotifier<String?>(null);
|
||||||
flightLastTripDateNotifier = ValueNotifier<String?>(null);
|
flightLastTripDateNotifier = ValueNotifier<String?>(null);
|
||||||
@ -161,15 +173,57 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Future<void> loadCountryList() async {
|
||||||
|
// setState(() {
|
||||||
|
// isCountryLoading = true;
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// final result = await apiService.fetchFlightsCountryList();
|
||||||
|
//
|
||||||
|
// if (result is List) {
|
||||||
|
// countryList =
|
||||||
|
// result.map((item) => Map<String, dynamic>.from(item)).toList();
|
||||||
|
// countryMap = {
|
||||||
|
// for (var item in countryList)
|
||||||
|
// if (item['country_code'] != null && item['country_name'] != null)
|
||||||
|
// item['country_code'] as String: item['country_name'] as String
|
||||||
|
// };
|
||||||
|
// countryCodes = countryMap.keys.toList();
|
||||||
|
// } else {
|
||||||
|
// countryList = [];
|
||||||
|
// countryMap = {};
|
||||||
|
// countryCodes = [];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// setState(() {
|
||||||
|
// isCountryLoading = false;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
Future<void> loadCountryList() async {
|
Future<void> loadCountryList() async {
|
||||||
|
setState(() {
|
||||||
|
isCountryLoading = true;
|
||||||
|
});
|
||||||
|
|
||||||
final result = await apiService.fetchFlightsCountryList();
|
final result = await apiService.fetchFlightsCountryList();
|
||||||
|
|
||||||
if (result is List) {
|
print("ResultCountry : $result");
|
||||||
countryList =
|
|
||||||
result.map((item) => Map<String, dynamic>.from(item)).toList();
|
// Create a map: Country_Code -> "City, Airport"
|
||||||
} else {
|
Map<String, String> tempCountryMap = {};
|
||||||
countryList = []; // fallback or throw error
|
|
||||||
|
for (var country in result) {
|
||||||
|
String city = country['City'] ?? '';
|
||||||
|
String airport = country['Airport'] ?? '';
|
||||||
|
String displayName = '${country['City']} - ${country['Airport']}';
|
||||||
|
|
||||||
|
tempCountryMap[country['Code']] = displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
countryMap = tempCountryMap; // Update the map
|
||||||
|
isCountryLoading = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int getRowCount() {
|
int getRowCount() {
|
||||||
@ -285,8 +339,12 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
for (int i = 1; i <= rowCount; i++) {
|
for (int i = 1; i <= rowCount; i++) {
|
||||||
final trip = {
|
final trip = {
|
||||||
"class": selectedClasses[i],
|
"class": selectedClasses[i],
|
||||||
"from_place": textControllers["_from${i}Controller"]?.text ?? "",
|
// "from_place": countryMap[selectedFrom[i]],
|
||||||
"to_place": textControllers["_to${i}Controller"]?.text ?? "",
|
"from_place": selectedFrom[i],
|
||||||
|
"to_place": selectedTo[i],
|
||||||
|
|
||||||
|
// "from_place": textControllers["_from${i}Controller"]?.text ?? "",
|
||||||
|
// "to_place": textControllers["_to${i}Controller"]?.text ?? "",
|
||||||
"date": textControllers["_date${i}Controller"]?.text ?? "",
|
"date": textControllers["_date${i}Controller"]?.text ?? "",
|
||||||
"time": textControllers["_time${i}Controller"]?.text ?? "",
|
"time": textControllers["_time${i}Controller"]?.text ?? "",
|
||||||
"created_by": widget.loginUser,
|
"created_by": widget.loginUser,
|
||||||
@ -377,10 +435,12 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
int index = i + 1; // Use 1-based indexing to match the form
|
int index = i + 1; // Use 1-based indexing to match the form
|
||||||
|
|
||||||
selectedClasses[index] = trip["class"].toString();
|
selectedClasses[index] = trip["class"].toString();
|
||||||
textControllers["_from${index}Controller"] =
|
selectedFrom[index] = trip["from_place"].toString();
|
||||||
TextEditingController(text: trip["from_place"]);
|
selectedTo[index] = trip["to_place"].toString();
|
||||||
textControllers["_to${index}Controller"] =
|
// textControllers["_from${index}Controller"] =
|
||||||
TextEditingController(text: trip["to_place"]);
|
// TextEditingController(text: trip["from_place"]);
|
||||||
|
// textControllers["_to${index}Controller"] =
|
||||||
|
// TextEditingController(text: trip["to_place"]);
|
||||||
textControllers["_date${index}Controller"] =
|
textControllers["_date${index}Controller"] =
|
||||||
TextEditingController(text: trip["date"]);
|
TextEditingController(text: trip["date"]);
|
||||||
textControllers["_time${index}Controller"] =
|
textControllers["_time${index}Controller"] =
|
||||||
@ -430,12 +490,19 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
|
|
||||||
// Loop through each trip row and validate required fields
|
// Loop through each trip row and validate required fields
|
||||||
for (int i = 1; i <= rowCount; i++) {
|
for (int i = 1; i <= rowCount; i++) {
|
||||||
if (textControllers["_from${i}Controller"]?.text.trim().isEmpty ?? true) {
|
// if (textControllers["_from${i}Controller"]?.text.trim().isEmpty ?? true) {
|
||||||
|
// errorMessages["from_place_$i"] = "Required";
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (selectedFrom[i] == null) {
|
||||||
errorMessages["from_place_$i"] = "Required";
|
errorMessages["from_place_$i"] = "Required";
|
||||||
}
|
}
|
||||||
if (textControllers["_to${i}Controller"]?.text.trim().isEmpty ?? true) {
|
if (selectedTo[i] == null) {
|
||||||
errorMessages["to_place_$i"] = "Required";
|
errorMessages["to_place_$i"] = "Required";
|
||||||
}
|
}
|
||||||
|
// if (textControllers["_to${i}Controller"]?.text.trim().isEmpty ?? true) {
|
||||||
|
// errorMessages["to_place_$i"] = "Required";
|
||||||
|
// }
|
||||||
if (textControllers["_date${i}Controller"]?.text.trim().isEmpty ?? true) {
|
if (textControllers["_date${i}Controller"]?.text.trim().isEmpty ?? true) {
|
||||||
errorMessages["date_$i"] = "Required";
|
errorMessages["date_$i"] = "Required";
|
||||||
}
|
}
|
||||||
@ -468,8 +535,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
int newIndex = 1;
|
int newIndex = 1;
|
||||||
for (int i = 1; i <= multiTripRowCount + 1; i++) {
|
for (int i = 1; i <= multiTripRowCount + 1; i++) {
|
||||||
if (i == index) continue; // Skip the deleted one
|
if (i == index) continue; // Skip the deleted one
|
||||||
updatedTextControllers["_from${newIndex}Controller"] =
|
// updatedTextControllers["_from${newIndex}Controller"] =
|
||||||
textControllers["_from${i}Controller"]!;
|
// textControllers["_from${i}Controller"]!;
|
||||||
updatedTextControllers["_to${newIndex}Controller"] =
|
updatedTextControllers["_to${newIndex}Controller"] =
|
||||||
textControllers["_to${i}Controller"]!;
|
textControllers["_to${i}Controller"]!;
|
||||||
updatedTextControllers["_date${newIndex}Controller"] =
|
updatedTextControllers["_date${newIndex}Controller"] =
|
||||||
@ -491,6 +558,27 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectedClasses = updatedClasses; // Update the map
|
selectedClasses = updatedClasses; // Update the map
|
||||||
|
|
||||||
|
// Shift the selectedFrom map BEFORE removing the index
|
||||||
|
Map<int, String?> updatedFrom = {};
|
||||||
|
newIndex = 1;
|
||||||
|
for (int i = 1; i <= selectedFrom.length; i++) {
|
||||||
|
if (i == index) continue; // Skip the one being deleted
|
||||||
|
updatedFrom[newIndex] = selectedFrom[i];
|
||||||
|
newIndex++;
|
||||||
|
}
|
||||||
|
selectedFrom = updatedFrom;
|
||||||
|
|
||||||
|
// Shift the selectedTo map BEFORE removing the index
|
||||||
|
Map<int, String?> updatedTo = {};
|
||||||
|
newIndex = 1;
|
||||||
|
for (int i = 1; i <= selectedTo.length; i++) {
|
||||||
|
if (i == index) continue; // Skip the one being deleted
|
||||||
|
updatedTo[newIndex] = selectedTo[i];
|
||||||
|
newIndex++;
|
||||||
|
}
|
||||||
|
selectedTo = updatedTo;
|
||||||
|
|
||||||
print("FlightData - $flightsData");
|
print("FlightData - $flightsData");
|
||||||
print("Updated Trips: $multiTripRowCount");
|
print("Updated Trips: $multiTripRowCount");
|
||||||
print("Updated Classes: $selectedClasses");
|
print("Updated Classes: $selectedClasses");
|
||||||
@ -916,7 +1004,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildSecondRow(bool isDesktop, int index) {
|
List<Widget> _buildSecondRow(bool isDesktop, int index) {
|
||||||
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
|
List<dynamic> purposeList = widget.apiDataForClass?['flight_class'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
@ -1020,18 +1108,18 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
late Map<String, String> countryMap; // Mapping country_code -> country_name
|
// late Map<String, String> countryMap; // Mapping country_code -> country_name
|
||||||
late List<String> countryCodes; // List of country codes
|
// late List<String> countryCodes; // List of country codes
|
||||||
|
// countryMap = {
|
||||||
|
// for (var item in countryList)
|
||||||
|
// if (item['country_code'] != null && item['country_name'] != null)
|
||||||
|
// item['country_code'] as String: item['country_name'] as String
|
||||||
|
// };
|
||||||
|
|
||||||
countryMap = {
|
// // Extract only country codes for processing
|
||||||
for (var item in countryList)
|
// countryCodes = countryMap.keys.toList();
|
||||||
item['country_code'] as String: item['country_name'] as String
|
//
|
||||||
};
|
// selectedCountry ??= null;
|
||||||
|
|
||||||
// Extract only country codes for processing
|
|
||||||
countryCodes = countryMap.keys.toList();
|
|
||||||
|
|
||||||
selectedCountry ??= null;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
@ -1053,16 +1141,19 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
// : MediaQuery.of(context).size.width * 0.66,
|
// : MediaQuery.of(context).size.width * 0.66,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: DropdownButtonFormField<String>(
|
child: isCountryLoading
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: DropdownButtonFormField<String>(
|
||||||
focusNode: focusNodes["_class${index}FocusNode"],
|
focusNode: focusNodes["_class${index}FocusNode"],
|
||||||
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||||
// controller: _hotelNameController,
|
// controller: _hotelNameController,
|
||||||
value: selectedClasses[index],
|
value: selectedClasses[index],
|
||||||
|
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
horizontal: 10), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: purposeList.isNotEmpty
|
onChanged: purposeList.isNotEmpty
|
||||||
? (newValue) {
|
? (newValue) {
|
||||||
@ -1103,68 +1194,71 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
isFocused: focusStates["_from${index}Focused"] ?? false,
|
isFocused: focusStates["_from${index}Focused"] ?? false,
|
||||||
// isFocused: focusStates["_from${fieldIndex}Focused"] ?? false,
|
// isFocused: focusStates["_from${fieldIndex}Focused"] ?? false,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
// child: SizedBox(
|
|
||||||
// height: 40,
|
|
||||||
// child: DropdownSearch<String>(
|
|
||||||
// selectedItem: countryMap[selectedCountry],
|
|
||||||
// popupProps: PopupProps.menu(
|
|
||||||
// showSearchBox: true, // Enables search functionality
|
|
||||||
// searchFieldProps: TextFieldProps(
|
|
||||||
// decoration: InputDecoration(
|
|
||||||
// hintText: "Search Country...",
|
|
||||||
// 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(
|
|
||||||
// // Center-align selected item
|
|
||||||
// alignment: Alignment.centerLeft,
|
|
||||||
// child: Text(
|
|
||||||
// selectedItem ?? "Select Country",
|
|
||||||
// style: TextStyle(fontSize: 12),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// onChanged: (String? newValue) {
|
|
||||||
// setState(() {
|
|
||||||
// // Find the country_code based on selected country_name
|
|
||||||
// selectedCountry = countryMap.entries
|
|
||||||
// .firstWhere((entry) => entry.value == newValue)
|
|
||||||
// .key;
|
|
||||||
//
|
|
||||||
// if (selectedCountry!.isNotEmpty) {
|
|
||||||
// errorMessages.remove("country_code");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// )
|
|
||||||
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: isCountryLoading
|
||||||
// focusNode: _fromFocusNode,
|
? Center(child: CircularProgressIndicator())
|
||||||
focusNode: focusNodes["_from${index}FocusNode"],
|
: DropdownSearch<String>(
|
||||||
controller: textControllers["_from${index}Controller"],
|
selectedItem: selectedFrom[index] != null
|
||||||
style: const TextStyle(fontSize: 12),
|
? countryMap[selectedFrom[index]]
|
||||||
decoration: const InputDecoration(
|
: null,
|
||||||
labelText: "From",
|
popupProps: PopupProps.menu(
|
||||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
showSearchBox: true,
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search ...",
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: countryMap.values.toList(),
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select",
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
// selectedFrom[index] = countryMap.entries
|
||||||
|
// .firstWhere((entry) => entry.value == newValue)
|
||||||
|
// .key;
|
||||||
|
|
||||||
|
selectedFrom[index] = countryMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
|
||||||
|
print(selectedFrom[index]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: 40,
|
||||||
|
// child: TextField(
|
||||||
|
// // focusNode: _fromFocusNode,
|
||||||
|
// focusNode: focusNodes["_from${index}FocusNode"],
|
||||||
|
// controller: textControllers["_from${index}Controller"],
|
||||||
|
// style: const TextStyle(fontSize: 12),
|
||||||
|
// decoration: const InputDecoration(
|
||||||
|
// labelText: "From",
|
||||||
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
|
// floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
|
// border: InputBorder.none,
|
||||||
|
// contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
),
|
||||||
if (errorMessages["from_place_$index"] != null) ...[
|
if (errorMessages["from_place_$index"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -1196,20 +1290,47 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: isCountryLoading
|
||||||
focusNode: focusNodes["_to${index}FocusNode"],
|
? Center(child: CircularProgressIndicator())
|
||||||
controller: textControllers["_to${index}Controller"],
|
: DropdownSearch<String>(
|
||||||
style: const TextStyle(fontSize: 12),
|
selectedItem: selectedTo[index] != null
|
||||||
decoration: const InputDecoration(
|
? countryMap[selectedTo[index]]
|
||||||
labelText: "To",
|
: null,
|
||||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
popupProps: PopupProps.menu(
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
showSearchBox: true,
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search ...",
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: countryMap.values.toList(),
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select Country",
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
selectedTo[index] = countryMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
|
||||||
|
print(selectedTo[index]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)),
|
||||||
if (errorMessages["to_place_$index"] != null) ...[
|
if (errorMessages["to_place_$index"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -1293,7 +1414,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
|||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
isFocused: focusStates["_timeFocused"] ?? false,
|
isFocused: focusStates["_timeFocused"] ?? false,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.08 : null,
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
|
import 'package:dropdown_search/dropdown_search.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
|
import '../../services/apiService.dart';
|
||||||
import '../../widgets/custom_text_field.dart';
|
import '../../widgets/custom_text_field.dart';
|
||||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||||
|
|
||||||
class TrainScreen extends StatefulWidget {
|
class TrainScreen extends StatefulWidget {
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
|
final Map<String, dynamic>? apiDataForClass;
|
||||||
final Function(Map<String, dynamic>) onSavetrain;
|
final Function(Map<String, dynamic>) onSavetrain;
|
||||||
final Function(bool) onClose;
|
final Function(bool) onClose;
|
||||||
final Map<String, dynamic>? selectedItem;
|
final Map<String, dynamic>? selectedItem;
|
||||||
@ -17,7 +20,8 @@ class TrainScreen extends StatefulWidget {
|
|||||||
this.apiData,
|
this.apiData,
|
||||||
required this.onSavetrain,
|
required this.onSavetrain,
|
||||||
required this.selectedItem,
|
required this.selectedItem,
|
||||||
required this.loginUser});
|
required this.loginUser,
|
||||||
|
this.apiDataForClass});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_TrainScreenState createState() => _TrainScreenState();
|
_TrainScreenState createState() => _TrainScreenState();
|
||||||
@ -26,6 +30,12 @@ class TrainScreen extends StatefulWidget {
|
|||||||
class _TrainScreenState extends State<TrainScreen> {
|
class _TrainScreenState extends State<TrainScreen> {
|
||||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
ApiService apiService = ApiService();
|
||||||
|
bool isCountryLoading = true;
|
||||||
|
Map<String, String> countryMap = {}; // <--- instead of late
|
||||||
|
|
||||||
|
late List<String> countryCodes;
|
||||||
|
|
||||||
Map<String, String?> selectedValues = {};
|
Map<String, String?> selectedValues = {};
|
||||||
|
|
||||||
final FocusNode _trainNoFocusNode = FocusNode();
|
final FocusNode _trainNoFocusNode = FocusNode();
|
||||||
@ -53,6 +63,8 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
bool _commentsFocus = false;
|
bool _commentsFocus = false;
|
||||||
|
|
||||||
String? selectedClass;
|
String? selectedClass;
|
||||||
|
String? selectedFrom;
|
||||||
|
String? selectedTo;
|
||||||
|
|
||||||
Map<String, String> errorMessages = {};
|
Map<String, String> errorMessages = {};
|
||||||
|
|
||||||
@ -60,8 +72,10 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
"train_no": _trainNoController.text,
|
"train_no": _trainNoController.text,
|
||||||
"class": selectedClass,
|
"class": selectedClass,
|
||||||
"from_station": _fromController.text,
|
"from_station": selectedFrom,
|
||||||
"to_station": _toController.text,
|
// "from_station": _fromController.text,
|
||||||
|
"to_station": selectedTo,
|
||||||
|
// "to_station": _toController.text,
|
||||||
"date": _dateController.text,
|
"date": _dateController.text,
|
||||||
"time": _timeController.text,
|
"time": _timeController.text,
|
||||||
"comments": _trainCommentsController.text,
|
"comments": _trainCommentsController.text,
|
||||||
@ -128,7 +142,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
|
|
||||||
_trainCommentsController = initController("comments");
|
_trainCommentsController = initController("comments");
|
||||||
_trainNoController = initController("train_no");
|
_trainNoController = initController("train_no");
|
||||||
_fromController = initController("from_station");
|
// _fromController = initController("from_station");
|
||||||
_toController = initController("to_station");
|
_toController = initController("to_station");
|
||||||
_dateController = initController("date");
|
_dateController = initController("date");
|
||||||
_timeController = initController("time");
|
_timeController = initController("time");
|
||||||
@ -138,11 +152,50 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
selectedClass = widget.selectedItem!["class"].toString();
|
selectedClass = widget.selectedItem!["class"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (widget.selectedItem != null &&
|
||||||
|
// widget.selectedItem!["from_station"] != null) {
|
||||||
|
// final fromCode = widget.selectedItem!["from_station"].toString();
|
||||||
|
// if (countryMap.containsKey(fromCode)) {
|
||||||
|
// selectedFrom = fromCode;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (widget.selectedItem != null &&
|
||||||
|
widget.selectedItem!["from_station"] != null) {
|
||||||
|
selectedFrom = widget.selectedItem!["from_station"].toString();
|
||||||
|
print("Selected From CODE = $selectedFrom");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.selectedItem != null &&
|
||||||
|
widget.selectedItem!["to_station"] != null) {
|
||||||
|
selectedTo = widget.selectedItem!["to_station"].toString();
|
||||||
|
print("Selected To CODE = $selectedTo");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (widget.selectedItem != null &&
|
||||||
|
// widget.selectedItem!["from_station"] != null) {
|
||||||
|
// String fromPlaceDisplay = widget.selectedItem!["from_station"].toString();
|
||||||
|
//
|
||||||
|
// selectedFrom = countryMap.entries
|
||||||
|
// .firstWhere((entry) => entry.value == fromPlaceDisplay,
|
||||||
|
// orElse: () => MapEntry('', '')) // avoid crash if not found
|
||||||
|
// .key;
|
||||||
|
//
|
||||||
|
// print("Selected From CODE = $selectedFrom");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (widget.selectedItem != null &&
|
||||||
|
// widget.selectedItem!["to_station"] != null) {
|
||||||
|
// selectedClass = widget.selectedItem!["to_station"].toString();
|
||||||
|
// }
|
||||||
|
|
||||||
_trainNoController.addListener(() => _clearError("train_no"));
|
_trainNoController.addListener(() => _clearError("train_no"));
|
||||||
_fromController.addListener(() => _clearError("from_station"));
|
// _fromController.addListener(() => _clearError("from_station"));
|
||||||
_toController.addListener(() => _clearError("to_station"));
|
_toController.addListener(() => _clearError("to_station"));
|
||||||
_dateController.addListener(() => _clearError("date"));
|
_dateController.addListener(() => _clearError("date"));
|
||||||
_timeController.addListener(() => _clearError("time"));
|
_timeController.addListener(() => _clearError("time"));
|
||||||
|
|
||||||
|
loadCountryList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -189,6 +242,32 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
return errorMessages.isEmpty; // Valid if there are no errors
|
return errorMessages.isEmpty; // Valid if there are no errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> loadCountryList() async {
|
||||||
|
setState(() {
|
||||||
|
isCountryLoading = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
final result = await apiService.fetchFlightsCountryList();
|
||||||
|
|
||||||
|
print("ResultCountry : $result");
|
||||||
|
|
||||||
|
// Create a map: Country_Code -> "City, Airport"
|
||||||
|
Map<String, String> tempCountryMap = {};
|
||||||
|
|
||||||
|
for (var country in result) {
|
||||||
|
String city = country['City'] ?? '';
|
||||||
|
String airport = country['Airport'] ?? '';
|
||||||
|
String displayName = '${country['City']} - ${country['Airport']}';
|
||||||
|
|
||||||
|
tempCountryMap[country['Code']] = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
countryMap = tempCountryMap; // Update the map
|
||||||
|
isCountryLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void handleSave() {
|
void handleSave() {
|
||||||
print("Handle Save accomadationData $trainData");
|
print("Handle Save accomadationData $trainData");
|
||||||
|
|
||||||
@ -413,7 +492,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
|
|
||||||
//----------------------------------------------
|
//----------------------------------------------
|
||||||
|
|
||||||
List<dynamic> purposeList = widget.apiData?['train_class'] ?? [];
|
List<dynamic> purposeList = widget.apiDataForClass?['train_class'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||||
.map((item) => DropdownMenuItem<String>(
|
.map((item) => DropdownMenuItem<String>(
|
||||||
@ -508,20 +587,80 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: isCountryLoading
|
||||||
focusNode: _fromFocusNode,
|
? Center(child: CircularProgressIndicator())
|
||||||
controller: _fromController,
|
: DropdownSearch<String>(
|
||||||
style: const TextStyle(fontSize: 12),
|
// selectedItem: selectedFrom != null
|
||||||
decoration: const InputDecoration(
|
// ? countryMap[selectedFrom]
|
||||||
labelText: "From",
|
// : null,
|
||||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
selectedItem: selectedFrom != null
|
||||||
|
? countryMap[
|
||||||
|
selectedFrom] // get the display value from code
|
||||||
|
: null,
|
||||||
|
popupProps: PopupProps.menu(
|
||||||
|
showSearchBox: true,
|
||||||
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search ...",
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
items: countryMap.values.toList(),
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select",
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// onChanged: (String? newValue) {
|
||||||
|
// setState(() {
|
||||||
|
// // selectedFrom[index] = countryMap.entries
|
||||||
|
// // .firstWhere((entry) => entry.value == newValue)
|
||||||
|
// // .key;
|
||||||
|
//
|
||||||
|
// selectedFrom = countryMap.entries
|
||||||
|
// .firstWhere((entry) => entry.value == newValue)
|
||||||
|
// .key;
|
||||||
|
//
|
||||||
|
// print(selectedFrom);
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
selectedFrom = countryMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: 40,
|
||||||
|
// child: TextField(
|
||||||
|
// focusNode: _fromFocusNode,
|
||||||
|
// controller: _fromController,
|
||||||
|
// style: const TextStyle(fontSize: 12),
|
||||||
|
// decoration: const InputDecoration(
|
||||||
|
// labelText: "From",
|
||||||
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
|
// floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
|
// border: InputBorder.none,
|
||||||
|
// contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
),
|
||||||
if (errorMessages["from_station"] != null) ...[
|
if (errorMessages["from_station"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
Text(
|
Text(
|
||||||
@ -553,19 +692,46 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: isCountryLoading
|
||||||
focusNode: _toFocusNode,
|
? Center(child: CircularProgressIndicator())
|
||||||
controller: _toController,
|
: DropdownSearch<String>(
|
||||||
style: const TextStyle(fontSize: 12),
|
selectedItem: selectedTo != null
|
||||||
decoration: const InputDecoration(
|
? countryMap[
|
||||||
labelText: "To",
|
selectedTo] // get the display value from code
|
||||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
: null,
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
popupProps: PopupProps.menu(
|
||||||
border: InputBorder.none,
|
showSearchBox: true,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
searchFieldProps: TextFieldProps(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: "Search ...",
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 10),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
items: countryMap.values.toList(),
|
||||||
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
|
dropdownSearchDecoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownBuilder: (context, selectedItem) => Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
selectedItem ?? "Select",
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
selectedTo = countryMap.entries
|
||||||
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
|
.key;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (errorMessages["to_station"] != null) ...[
|
if (errorMessages["to_station"] != null) ...[
|
||||||
SizedBox(height: 5), // Space before error message
|
SizedBox(height: 5), // Space before error message
|
||||||
@ -649,7 +815,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
|||||||
CustomTextFieldItnerarySubWrapper(
|
CustomTextFieldItnerarySubWrapper(
|
||||||
isFocused: _timeFocus,
|
isFocused: _timeFocus,
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.08 : null,
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
|
|||||||
@ -1,28 +1,106 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class FlightListWidget extends StatelessWidget {
|
import '../../services/apiService.dart';
|
||||||
|
|
||||||
|
class FlightListWidget extends StatefulWidget {
|
||||||
|
final bool hasAction;
|
||||||
|
final String? tripType;
|
||||||
final List<Map<String, dynamic>> flightList;
|
final List<Map<String, dynamic>> flightList;
|
||||||
final Function(bool, Map<String, dynamic>, String) onOpen;
|
final Function(bool, Map<String, dynamic>, String) onOpen;
|
||||||
final Function(Map<String, dynamic>) onDeleteFlight;
|
final Function(Map<String, dynamic>) onDeleteFlight;
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
|
|
||||||
final Function(String, bool) onAddNew;
|
final Function(String, bool) onAddNew;
|
||||||
final bool isViewMode;
|
final bool isViewMode;
|
||||||
|
|
||||||
const FlightListWidget(
|
const FlightListWidget({
|
||||||
{super.key,
|
Key? key,
|
||||||
required this.flightList,
|
required this.flightList,
|
||||||
required this.onOpen,
|
required this.onOpen,
|
||||||
required this.onDeleteFlight,
|
required this.onDeleteFlight,
|
||||||
required this.onAddNew,
|
required this.onAddNew,
|
||||||
required this.apiData,
|
required this.apiData,
|
||||||
required this.isViewMode});
|
required this.isViewMode,
|
||||||
|
required this.hasAction,
|
||||||
|
this.tripType,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_FlightListWidgetState createState() => _FlightListWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FlightListWidgetState extends State<FlightListWidget> {
|
||||||
|
ApiService apiService = ApiService();
|
||||||
|
|
||||||
|
// late Map<String, String> countryMap;
|
||||||
|
Map<String, String> countryMap = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
loadCountryList(); // Call your method here
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadCountryList() async {
|
||||||
|
final result = await apiService.fetchFlightsCountryList();
|
||||||
|
|
||||||
|
print("ResultCountry : $result");
|
||||||
|
|
||||||
|
// Create a map: Country_Code -> "City, Airport"
|
||||||
|
Map<String, String> tempCountryMap = {};
|
||||||
|
|
||||||
|
for (var country in result) {
|
||||||
|
String city = country['City'] ?? '';
|
||||||
|
String airport = country['Airport'] ?? '';
|
||||||
|
String displayName = '${country['City']} - ${country['Airport']}';
|
||||||
|
// String displayName = '${country['City']} | ${country['Airport']}';
|
||||||
|
|
||||||
|
tempCountryMap[country['Code']] = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
countryMap = tempCountryMap; // Update the map
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
final isDesktop = MediaQuery.of(context).size.width > 1024;
|
||||||
|
|
||||||
|
ApiService apiService = ApiService();
|
||||||
|
|
||||||
|
late Map<String, String> countryMap;
|
||||||
|
late List<String> countryCodes;
|
||||||
|
|
||||||
|
void checkClass() {
|
||||||
|
if (widget.hasAction) {
|
||||||
|
if (widget.tripType?.isNotEmpty == true) {
|
||||||
|
print("Teppp - $widget.tripType");
|
||||||
|
widget.onAddNew("Flight", true);
|
||||||
|
} else {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Select Trip Type'),
|
||||||
|
content: const Text(
|
||||||
|
'Please select a trip type before adding a flight.'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("Teppp No - $widget.tripType");
|
||||||
|
widget.onAddNew("Flight", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -39,15 +117,15 @@ class FlightListWidget extends StatelessWidget {
|
|||||||
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
// ),
|
// ),
|
||||||
MouseRegion(
|
MouseRegion(
|
||||||
cursor: isViewMode
|
cursor: widget.isViewMode
|
||||||
? SystemMouseCursors.forbidden
|
? SystemMouseCursors.forbidden
|
||||||
: SystemMouseCursors.click,
|
: SystemMouseCursors.click,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: isViewMode
|
onTap: widget.isViewMode
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
|
checkClass();
|
||||||
print("New data");
|
print("New data");
|
||||||
onAddNew("Flight", true);
|
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize:
|
mainAxisSize:
|
||||||
@ -81,10 +159,10 @@ class FlightListWidget extends StatelessWidget {
|
|||||||
|
|
||||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||||
List<Map<String, dynamic>> filteredList =
|
List<Map<String, dynamic>> filteredList =
|
||||||
flightList.where((item) => item["is_active"] == "1").toList();
|
widget.flightList.where((item) => item["is_active"] == "1").toList();
|
||||||
print("filteredList- $filteredList");
|
print("filteredList- $filteredList");
|
||||||
|
|
||||||
List<dynamic> visatypeList = apiData?['flight_class'] ?? [];
|
List<dynamic> visatypeList = widget.apiData?['flight_class'] ?? [];
|
||||||
|
|
||||||
String getRequestForClass(String? specialRequestKey) {
|
String getRequestForClass(String? specialRequestKey) {
|
||||||
if (specialRequestKey == null) return "N/A";
|
if (specialRequestKey == null) return "N/A";
|
||||||
@ -174,13 +252,13 @@ class FlightListWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => onOpen(true, item, "Flight"),
|
onTap: () => widget.onOpen(true, item, "Flight"),
|
||||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||||
width: 20, height: 15),
|
width: 20, height: 15),
|
||||||
),
|
),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => onDeleteFlight(item),
|
onTap: () => widget.onDeleteFlight(item),
|
||||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||||
width: 20, height: 15),
|
width: 20, height: 15),
|
||||||
),
|
),
|
||||||
@ -224,6 +302,13 @@ class FlightListWidget extends StatelessWidget {
|
|||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
if (item["trips"] != null && item["trips"].isNotEmpty)
|
if (item["trips"] != null && item["trips"].isNotEmpty)
|
||||||
...item["trips"].map<Widget>((trip) {
|
...item["trips"].map<Widget>((trip) {
|
||||||
|
String fromPlaceCountry =
|
||||||
|
countryMap[trip["from_place"]?.toString()] ??
|
||||||
|
"Unknown Country";
|
||||||
|
String toPlaceCountry =
|
||||||
|
countryMap[trip["to_place"]?.toString()] ??
|
||||||
|
"Unknown Country";
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -240,7 +325,8 @@ class FlightListWidget extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
"${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
"$fromPlaceCountry (from) - (to) $toPlaceCountry",
|
||||||
|
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class TrainListWidget extends StatelessWidget {
|
import '../../services/apiService.dart';
|
||||||
|
|
||||||
|
class TrainListWidget extends StatefulWidget {
|
||||||
|
final bool hasAction;
|
||||||
|
final String? tripType;
|
||||||
final List<Map<String, dynamic>> trainList;
|
final List<Map<String, dynamic>> trainList;
|
||||||
final Function(bool, Map<String, dynamic>, String) onOpen;
|
final Function(bool, Map<String, dynamic>, String) onOpen;
|
||||||
final Function(Map<String, dynamic>) onDeleteTrain;
|
final Function(Map<String, dynamic>) onDeleteTrain;
|
||||||
@ -10,14 +14,83 @@ class TrainListWidget extends StatelessWidget {
|
|||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
|
|
||||||
const TrainListWidget({
|
const TrainListWidget({
|
||||||
super.key,
|
Key? key,
|
||||||
required this.trainList,
|
required this.trainList,
|
||||||
required this.onOpen,
|
required this.onOpen,
|
||||||
required this.onDeleteTrain,
|
required this.onDeleteTrain,
|
||||||
required this.onAddNew,
|
required this.onAddNew,
|
||||||
required this.isViewMode,
|
required this.isViewMode,
|
||||||
required this.apiData,
|
required this.apiData,
|
||||||
|
required this.hasAction,
|
||||||
|
this.tripType,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_TrainListWidgetState createState() => _TrainListWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TrainListWidgetState extends State<TrainListWidget> {
|
||||||
|
ApiService apiService = ApiService();
|
||||||
|
|
||||||
|
// late Map<String, String> countryMap;
|
||||||
|
Map<String, String> countryMap = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
loadCountryList(); // Call your method here
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkClass() {
|
||||||
|
if (widget.hasAction) {
|
||||||
|
if (widget.tripType?.isNotEmpty == true) {
|
||||||
|
print("Teppp - $widget.tripType");
|
||||||
|
widget.onAddNew("Train", true);
|
||||||
|
} else {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Select Trip Type'),
|
||||||
|
content: const Text(
|
||||||
|
'Please select a trip type before adding a Train.'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("Teppp No - $widget.tripType");
|
||||||
|
widget.onAddNew("Flight", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadCountryList() async {
|
||||||
|
final result = await apiService.fetchFlightsCountryList();
|
||||||
|
|
||||||
|
print("ResultCountry : $result");
|
||||||
|
|
||||||
|
// Create a map: Country_Code -> "City, Airport"
|
||||||
|
Map<String, String> tempCountryMap = {};
|
||||||
|
|
||||||
|
for (var country in result) {
|
||||||
|
String city = country['City'] ?? '';
|
||||||
|
String airport = country['Airport'] ?? '';
|
||||||
|
String displayName = '${country['City']} - ${country['Airport']}';
|
||||||
|
// String displayName = '${country['City']} | ${country['Airport']}';
|
||||||
|
|
||||||
|
tempCountryMap[country['Code']] = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
countryMap = tempCountryMap; // Update the map
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -35,20 +108,20 @@ class TrainListWidget extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
MouseRegion(
|
MouseRegion(
|
||||||
cursor: isViewMode
|
cursor: widget.isViewMode
|
||||||
? SystemMouseCursors.forbidden
|
? SystemMouseCursors.forbidden
|
||||||
: SystemMouseCursors.click,
|
: SystemMouseCursors.click,
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
cursor: isViewMode
|
cursor: widget.isViewMode
|
||||||
? SystemMouseCursors.forbidden
|
? SystemMouseCursors.forbidden
|
||||||
: SystemMouseCursors.click,
|
: SystemMouseCursors.click,
|
||||||
|
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: isViewMode
|
onTap: widget.isViewMode
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
print("New data");
|
print("New data");
|
||||||
onAddNew("Train", true);
|
checkClass();
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize:
|
mainAxisSize:
|
||||||
@ -130,10 +203,10 @@ class TrainListWidget extends StatelessWidget {
|
|||||||
|
|
||||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||||
List<Map<String, dynamic>> filteredList =
|
List<Map<String, dynamic>> filteredList =
|
||||||
trainList.where((item) => item["is_active"] == "1").toList();
|
widget.trainList.where((item) => item["is_active"] == "1").toList();
|
||||||
// print("filteredList- $filteredList");
|
// print("filteredList- $filteredList");
|
||||||
|
|
||||||
List<dynamic> trainClassList = apiData?['train_class'] ?? [];
|
List<dynamic> trainClassList = widget.apiData?['train_class'] ?? [];
|
||||||
|
|
||||||
String getRequestForTrainClass(String? specialRequestKey) {
|
String getRequestForTrainClass(String? specialRequestKey) {
|
||||||
if (specialRequestKey == null) return "N/A";
|
if (specialRequestKey == null) return "N/A";
|
||||||
@ -180,6 +253,11 @@ class TrainListWidget extends StatelessWidget {
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = filteredList[index];
|
final item = filteredList[index];
|
||||||
|
|
||||||
|
String fromPlaceCountry =
|
||||||
|
countryMap[item["from_station"].toString()] ?? "Unknown Country";
|
||||||
|
String toPlaceCountry =
|
||||||
|
countryMap[item["to_station"].toString()] ?? "Unknown Country";
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -217,13 +295,13 @@ class TrainListWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => onOpen(true, item, "Train"),
|
onTap: () => widget.onOpen(true, item, "Train"),
|
||||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||||
width: 20, height: 15),
|
width: 20, height: 15),
|
||||||
),
|
),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => onDeleteTrain(item),
|
onTap: () => widget.onDeleteTrain(item),
|
||||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||||
width: 20, height: 15),
|
width: 20, height: 15),
|
||||||
),
|
),
|
||||||
@ -284,7 +362,9 @@ class TrainListWidget extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
"${item["from_station"]!} - ${(item["to_station"])}",
|
"$fromPlaceCountry (from) - (to) $toPlaceCountry",
|
||||||
|
|
||||||
|
// "${item["from_station"]!} - ${(item["to_station"])}",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|||||||
@ -284,6 +284,9 @@ class CreateNewPlan extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CreateNewPlansState extends State<CreateNewPlan> {
|
class CreateNewPlansState extends State<CreateNewPlan> {
|
||||||
|
final GlobalKey<DynamicItineraryState> dynamicItineraryKey =
|
||||||
|
GlobalKey<DynamicItineraryState>();
|
||||||
|
|
||||||
final ApiService apiService = ApiService();
|
final ApiService apiService = ApiService();
|
||||||
|
|
||||||
final TextEditingController _tripTitleController = TextEditingController();
|
final TextEditingController _tripTitleController = TextEditingController();
|
||||||
@ -311,12 +314,14 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
late Color layoutColorForUser;
|
late Color layoutColorForUser;
|
||||||
|
|
||||||
Map<String, dynamic>? apiData; // Store API response here
|
Map<String, dynamic>? apiData; // Store API response here
|
||||||
|
Map<String, dynamic>? apiDataForClass; // Store API response here
|
||||||
List<dynamic>? apiCountryData;
|
List<dynamic>? apiCountryData;
|
||||||
List<dynamic>? apiCostData; // Store API response here
|
List<dynamic>? apiCostData; // Store API response here
|
||||||
bool isLoading = true; // Track loading state
|
bool isLoading = true; // Track loading state
|
||||||
String? TripPlanAction;
|
String? TripPlanAction;
|
||||||
bool showDomestic = false;
|
bool showDomestic = false;
|
||||||
bool showInternational = false;
|
bool showInternational = false;
|
||||||
|
bool hasAction = true;
|
||||||
|
|
||||||
late Map<String, String> costCenterMap;
|
late Map<String, String> costCenterMap;
|
||||||
List<String> costCenterIds = [];
|
List<String> costCenterIds = [];
|
||||||
@ -511,6 +516,12 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
widget.selectedPlanData['miscellaneous'] ?? []);
|
widget.selectedPlanData['miscellaneous'] ?? []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (widget.selectedPlanData['trip_type'] != null) {
|
||||||
|
int? tripId =
|
||||||
|
int.tryParse(widget.selectedPlanData['trip_type'].toString());
|
||||||
|
fetchTrainFlightClass(tripId!);
|
||||||
|
}
|
||||||
|
|
||||||
if (widget.selectedPlanData.containsKey('plan_id') &&
|
if (widget.selectedPlanData.containsKey('plan_id') &&
|
||||||
widget.selectedPlanData['plan_id'] != null) {
|
widget.selectedPlanData['plan_id'] != null) {
|
||||||
print("Plan ID exists: ${widget.selectedPlanData['plan_id']}");
|
print("Plan ID exists: ${widget.selectedPlanData['plan_id']}");
|
||||||
@ -528,15 +539,19 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
if (TripPlanAction == "Plan Creation Not Allowed") {
|
if (TripPlanAction == "Plan Creation Not Allowed") {
|
||||||
showDomestic = false;
|
showDomestic = false;
|
||||||
showInternational = false;
|
showInternational = false;
|
||||||
|
hasAction = false;
|
||||||
} else if (TripPlanAction == "Only Domestic Plan Creation Allowed") {
|
} else if (TripPlanAction == "Only Domestic Plan Creation Allowed") {
|
||||||
showDomestic = true;
|
showDomestic = true;
|
||||||
showInternational = false;
|
showInternational = false;
|
||||||
|
hasAction = true;
|
||||||
} else if (TripPlanAction == "Only International Plan Creation Allowed") {
|
} else if (TripPlanAction == "Only International Plan Creation Allowed") {
|
||||||
showDomestic = false;
|
showDomestic = false;
|
||||||
showInternational = true;
|
showInternational = true;
|
||||||
|
hasAction = true;
|
||||||
} else if (TripPlanAction == "Both Type Plan Creation Allowed") {
|
} else if (TripPlanAction == "Both Type Plan Creation Allowed") {
|
||||||
showDomestic = true;
|
showDomestic = true;
|
||||||
showInternational = true;
|
showInternational = true;
|
||||||
|
hasAction = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -764,6 +779,55 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> fetchTrainFlightClass(int tripId) async {
|
||||||
|
final userId = (planUsrId?.toString().isNotEmpty == true)
|
||||||
|
? planUsrId.toString()
|
||||||
|
: (planTravlrId?.toString().isNotEmpty == true)
|
||||||
|
? planTravlrId.toString()
|
||||||
|
: '';
|
||||||
|
|
||||||
|
// final String apiUrldata = '$apiUrl/api/getDropdownMaster';
|
||||||
|
final String apiUrldata =
|
||||||
|
'$apiUrl/api/getFlightAndTrainClass?user_id=$userId&trip_type=$tripId';
|
||||||
|
|
||||||
|
final token = await getToken();
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
try {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
print(data);
|
||||||
|
|
||||||
|
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||||
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a Map");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> plansJson =
|
||||||
|
data['data']; // 'data' is a Map, not a List
|
||||||
|
setState(() {
|
||||||
|
apiDataForClass = plansJson; // Store API response in state
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Error parsing response: $e');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load plans');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle Submit
|
// Handle Submit
|
||||||
|
|
||||||
bool validateForm() {
|
bool validateForm() {
|
||||||
@ -1213,7 +1277,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: DynamicItinerary(
|
child: DynamicItinerary(
|
||||||
|
key: dynamicItineraryKey,
|
||||||
|
hasAction: hasAction,
|
||||||
|
tripType: _selectedTripType,
|
||||||
apiData: apiData,
|
apiData: apiData,
|
||||||
|
apiDataForClass: apiDataForClass,
|
||||||
apiCountryData: apiCountryData,
|
apiCountryData: apiCountryData,
|
||||||
onItineraryUpdate: handleItineraryUpdate,
|
onItineraryUpdate: handleItineraryUpdate,
|
||||||
loginUser: selfId,
|
loginUser: selfId,
|
||||||
@ -1588,7 +1656,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Purpose of Travel *", // Your label
|
"Purpose of Trip *", // Your label
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -1887,6 +1955,9 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
: () {
|
: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedTripType = "1";
|
_selectedTripType = "1";
|
||||||
|
fetchTrainFlightClass(1);
|
||||||
|
|
||||||
|
dynamicItineraryKey.currentState?.updateSelectedServices();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: CustomTextFieldWrapper(
|
child: CustomTextFieldWrapper(
|
||||||
@ -1944,6 +2015,8 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
|||||||
: () {
|
: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedTripType = "2";
|
_selectedTripType = "2";
|
||||||
|
fetchTrainFlightClass(2);
|
||||||
|
dynamicItineraryKey.currentState?.updateSelectedServices();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: CustomTextFieldWrapper(
|
child: CustomTextFieldWrapper(
|
||||||
|
|||||||
@ -25,7 +25,10 @@ import '../itnerary_list/miscellaneous_list.dart';
|
|||||||
import '../itnerary_list/visa_list.dart';
|
import '../itnerary_list/visa_list.dart';
|
||||||
|
|
||||||
class DynamicItinerary extends StatefulWidget {
|
class DynamicItinerary extends StatefulWidget {
|
||||||
|
final bool hasAction;
|
||||||
|
final String? tripType;
|
||||||
final Map<String, dynamic>? apiData;
|
final Map<String, dynamic>? apiData;
|
||||||
|
final Map<String, dynamic>? apiDataForClass;
|
||||||
final List<dynamic>? apiCountryData;
|
final List<dynamic>? apiCountryData;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
final Function(String, List<Map<String, dynamic>>)
|
final Function(String, List<Map<String, dynamic>>)
|
||||||
@ -40,15 +43,19 @@ class DynamicItinerary extends StatefulWidget {
|
|||||||
required this.apiCountryData,
|
required this.apiCountryData,
|
||||||
required this.loginUser,
|
required this.loginUser,
|
||||||
required this.selectedPlanData,
|
required this.selectedPlanData,
|
||||||
required this.isViewMode});
|
required this.isViewMode,
|
||||||
|
required this.hasAction,
|
||||||
|
this.tripType,
|
||||||
|
this.apiDataForClass});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_DynamicItineraryState createState() => _DynamicItineraryState();
|
DynamicItineraryState createState() => DynamicItineraryState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DynamicItineraryState extends State<DynamicItinerary> {
|
class DynamicItineraryState extends State<DynamicItinerary> {
|
||||||
final ApiService apiService = ApiService();
|
final ApiService apiService = ApiService();
|
||||||
|
|
||||||
|
String? _tripType;
|
||||||
String selectedOption = "";
|
String selectedOption = "";
|
||||||
String selectedListOption = "";
|
String selectedListOption = "";
|
||||||
|
|
||||||
@ -80,6 +87,25 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
handleSelectedPlan();
|
handleSelectedPlan();
|
||||||
updateSelectedServices();
|
updateSelectedServices();
|
||||||
|
_tripType = widget.tripType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
if (widget.tripType != _tripType) {
|
||||||
|
updateTripType(widget.tripType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateTripType(String? newTripType) {
|
||||||
|
if (_tripType != newTripType) {
|
||||||
|
setState(() {
|
||||||
|
_tripType = newTripType;
|
||||||
|
});
|
||||||
|
updateSelectedServices(); // Refresh services based on new tripType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadAllServices() async {
|
Future<void> loadAllServices() async {
|
||||||
@ -126,31 +152,108 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> getAllowedServiceNames() {
|
||||||
|
if (widget.tripType == "1") {
|
||||||
|
return ["flight", "accomodation", "train", "bus"];
|
||||||
|
} else if (widget.tripType == "2") {
|
||||||
|
return [
|
||||||
|
"flight",
|
||||||
|
"accomodation",
|
||||||
|
"forex",
|
||||||
|
"insurance",
|
||||||
|
"visa",
|
||||||
|
"miscellaneous"
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// tripType is null or not 1/2, allow everything
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Future<void> updateSelectedServices() async {
|
||||||
|
// await loadAllServices();
|
||||||
|
// await loadOrgSelectedAlServices();
|
||||||
|
//
|
||||||
|
// if (hasAnyItineraryData()) {
|
||||||
|
// print("SELCTSplanChhose: ${filledItineraryKeys}");
|
||||||
|
//
|
||||||
|
// final selectedIds =
|
||||||
|
// selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||||
|
//
|
||||||
|
// // Filter services that match filled keys (name match) and are not already selected
|
||||||
|
// final additionalServices = selectedAllServices!.where((service) {
|
||||||
|
// final name = (service['name'] ?? "").toString().toLowerCase();
|
||||||
|
// final id = service['service_id'].toString();
|
||||||
|
// return filledItineraryKeys.contains(name) && !selectedIds.contains(id);
|
||||||
|
// }).toList();
|
||||||
|
//
|
||||||
|
// final originalFiltered = selectedAllServices!
|
||||||
|
// .where((service) =>
|
||||||
|
// selectedIds.contains(service['service_id'].toString()))
|
||||||
|
// .toList();
|
||||||
|
//
|
||||||
|
// // setState(() {
|
||||||
|
// // ServicesChoosed = [...originalFiltered, ...additionalServices];
|
||||||
|
// // });
|
||||||
|
// setState(() {
|
||||||
|
// ServicesChoosed = [...originalFiltered, ...additionalServices]
|
||||||
|
// ..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// print(
|
||||||
|
// "Services chosen based on filled keys + selected: $ServicesChoosed");
|
||||||
|
// } else {
|
||||||
|
// final selectedIds =
|
||||||
|
// selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||||
|
//
|
||||||
|
// final filtered = selectedAllServices!
|
||||||
|
// .where((service) =>
|
||||||
|
// selectedIds.contains(service['service_id'].toString()))
|
||||||
|
// .toList();
|
||||||
|
//
|
||||||
|
// setState(() {
|
||||||
|
// ServicesChoosed = filtered
|
||||||
|
// ..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// // setState(() {
|
||||||
|
// // ServicesChoosed = filtered;
|
||||||
|
// // });
|
||||||
|
//
|
||||||
|
// print("Filtered Selected Services Chooesed: $ServicesChoosed");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
Future<void> updateSelectedServices() async {
|
Future<void> updateSelectedServices() async {
|
||||||
await loadAllServices();
|
await loadAllServices();
|
||||||
await loadOrgSelectedAlServices();
|
await loadOrgSelectedAlServices();
|
||||||
|
|
||||||
|
final allowedServiceNames = getAllowedServiceNames();
|
||||||
|
|
||||||
if (hasAnyItineraryData()) {
|
if (hasAnyItineraryData()) {
|
||||||
print("SELCTSplanChhose: ${filledItineraryKeys}");
|
print("SELCTSplanChhose: $filledItineraryKeys");
|
||||||
|
|
||||||
final selectedIds =
|
final selectedIds =
|
||||||
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||||
|
|
||||||
// Filter services that match filled keys (name match) and are not already selected
|
|
||||||
final additionalServices = selectedAllServices!.where((service) {
|
final additionalServices = selectedAllServices!.where((service) {
|
||||||
final name = (service['name'] ?? "").toString().toLowerCase();
|
final name = (service['name'] ?? "").toString().toLowerCase();
|
||||||
final id = service['service_id'].toString();
|
final id = service['service_id'].toString();
|
||||||
return filledItineraryKeys.contains(name) && !selectedIds.contains(id);
|
final isNameAllowed =
|
||||||
|
allowedServiceNames.isEmpty || allowedServiceNames.contains(name);
|
||||||
|
return filledItineraryKeys.contains(name) &&
|
||||||
|
!selectedIds.contains(id) &&
|
||||||
|
isNameAllowed;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
final originalFiltered = selectedAllServices!
|
final originalFiltered = selectedAllServices!.where((service) {
|
||||||
.where((service) =>
|
final name = (service['name'] ?? "").toString().toLowerCase();
|
||||||
selectedIds.contains(service['service_id'].toString()))
|
final id = service['service_id'].toString();
|
||||||
.toList();
|
final isNameAllowed =
|
||||||
|
allowedServiceNames.isEmpty || allowedServiceNames.contains(name);
|
||||||
|
return selectedIds.contains(id) && isNameAllowed;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
// setState(() {
|
|
||||||
// ServicesChoosed = [...originalFiltered, ...additionalServices];
|
|
||||||
// });
|
|
||||||
setState(() {
|
setState(() {
|
||||||
ServicesChoosed = [...originalFiltered, ...additionalServices]
|
ServicesChoosed = [...originalFiltered, ...additionalServices]
|
||||||
..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
||||||
@ -162,21 +265,20 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
final selectedIds =
|
final selectedIds =
|
||||||
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||||
|
|
||||||
final filtered = selectedAllServices!
|
final filtered = selectedAllServices!.where((service) {
|
||||||
.where((service) =>
|
final name = (service['name'] ?? "").toString().toLowerCase();
|
||||||
selectedIds.contains(service['service_id'].toString()))
|
final isNameAllowed =
|
||||||
.toList();
|
allowedServiceNames.isEmpty || allowedServiceNames.contains(name);
|
||||||
|
return selectedIds.contains(service['service_id'].toString()) &&
|
||||||
|
isNameAllowed;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
ServicesChoosed = filtered
|
ServicesChoosed = filtered
|
||||||
..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
// setState(() {
|
print("Filtered Selected Services Chosen: $ServicesChoosed");
|
||||||
// ServicesChoosed = filtered;
|
|
||||||
// });
|
|
||||||
|
|
||||||
print("Filtered Selected Services Chooesed: $ServicesChoosed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,6 +510,8 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
switch (selectedListOption) {
|
switch (selectedListOption) {
|
||||||
case "Train":
|
case "Train":
|
||||||
selectedListWidget = TrainListWidget(
|
selectedListWidget = TrainListWidget(
|
||||||
|
hasAction: widget.hasAction,
|
||||||
|
tripType: widget.tripType,
|
||||||
trainList: itineraryData["Train"]!,
|
trainList: itineraryData["Train"]!,
|
||||||
onOpen: handleEdit,
|
onOpen: handleEdit,
|
||||||
onAddNew: handlecreateNewPlan,
|
onAddNew: handlecreateNewPlan,
|
||||||
@ -491,6 +595,8 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
case "Flight":
|
case "Flight":
|
||||||
default:
|
default:
|
||||||
selectedListWidget = FlightListWidget(
|
selectedListWidget = FlightListWidget(
|
||||||
|
hasAction: widget.hasAction,
|
||||||
|
tripType: widget.tripType,
|
||||||
flightList: itineraryData["Flight"]!,
|
flightList: itineraryData["Flight"]!,
|
||||||
onOpen: handleEdit,
|
onOpen: handleEdit,
|
||||||
onAddNew: handlecreateNewPlan,
|
onAddNew: handlecreateNewPlan,
|
||||||
@ -505,6 +611,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
selectedWidget = TrainScreen(
|
selectedWidget = TrainScreen(
|
||||||
onClose: handleClose,
|
onClose: handleClose,
|
||||||
apiData: widget.apiData,
|
apiData: widget.apiData,
|
||||||
|
apiDataForClass: widget.apiDataForClass,
|
||||||
loginUser: widget.loginUser,
|
loginUser: widget.loginUser,
|
||||||
onSavetrain: (data) => handleItineraryUpdate("Train", data),
|
onSavetrain: (data) => handleItineraryUpdate("Train", data),
|
||||||
selectedItem: selectedItem);
|
selectedItem: selectedItem);
|
||||||
@ -582,10 +689,13 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
|||||||
case "Flight":
|
case "Flight":
|
||||||
default:
|
default:
|
||||||
selectedWidget = FlightScreen(
|
selectedWidget = FlightScreen(
|
||||||
|
hasAction: widget.hasAction,
|
||||||
|
tripType: widget.tripType,
|
||||||
onClose: handleClose,
|
onClose: handleClose,
|
||||||
loginUser: widget.loginUser,
|
loginUser: widget.loginUser,
|
||||||
onSaveFlight: (data) => handleItineraryUpdate("Flight", data),
|
onSaveFlight: (data) => handleItineraryUpdate("Flight", data),
|
||||||
apiData: widget.apiData,
|
apiData: widget.apiData,
|
||||||
|
apiDataForClass: widget.apiDataForClass,
|
||||||
selectedItem: selectedItem,
|
selectedItem: selectedItem,
|
||||||
flightData: itineraryData["Flight"]!,
|
flightData: itineraryData["Flight"]!,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -36,6 +36,10 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
Color? layoutColor;
|
Color? layoutColor;
|
||||||
Color? bodyColor;
|
Color? bodyColor;
|
||||||
|
|
||||||
|
List<Plan> allPlans = [];
|
||||||
|
List<Plan> filteredPlans = [];
|
||||||
|
TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -44,11 +48,33 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
initializeData();
|
initializeData();
|
||||||
loadInitialData();
|
loadInitialData();
|
||||||
|
|
||||||
|
futurePlans.then((plans) {
|
||||||
|
setState(() {
|
||||||
|
allPlans = plans;
|
||||||
|
filteredPlans = plans;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// futurePlans = fetchPlans();
|
// futurePlans = fetchPlans();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void filterPlans(String query) {
|
||||||
|
final lowerQuery = query.toLowerCase();
|
||||||
|
setState(() {
|
||||||
|
filteredPlans = allPlans.where((plan) {
|
||||||
|
return (plan.planId?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
|
(plan.tripTitle?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
|
(plan.userName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
|
(plan.travellerName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
|
(plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
|
(plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
|
(plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false);
|
||||||
|
}).toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void loadInitialData() async {
|
void loadInitialData() async {
|
||||||
String? layoutString = await getLayoutColor();
|
String? layoutString = await getLayoutColor();
|
||||||
String? bodyStringColor = await getBodyColor();
|
String? bodyStringColor = await getBodyColor();
|
||||||
@ -322,7 +348,7 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Text('Plans List',
|
const Text('Trip List',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@ -334,9 +360,9 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
Spacer(),
|
Spacer(),
|
||||||
Container(
|
Container(
|
||||||
width: MediaQuery.of(context).size.width * 0.2,
|
width: MediaQuery.of(context).size.width * 0.2,
|
||||||
// or use Flexible
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
onChanged: (query) {},
|
controller: searchController,
|
||||||
|
onChanged: filterPlans,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search for a plan",
|
hintText: "Search for a plan",
|
||||||
hintStyle:
|
hintStyle:
|
||||||
@ -351,7 +377,6 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
color: Colors.grey.shade300, width: 0.5),
|
color: Colors.grey.shade300, width: 0.5),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
// borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide:
|
borderSide:
|
||||||
BorderSide(color: Colors.blueAccent, width: 1),
|
BorderSide(color: Colors.blueAccent, width: 1),
|
||||||
),
|
),
|
||||||
@ -510,7 +535,7 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
),
|
),
|
||||||
columns: const [
|
columns: const [
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('Plan Id',
|
label: Text('Trip Id',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Color(0xFF9E9DBD),
|
color: Color(0xFF9E9DBD),
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@ -523,7 +548,7 @@ class _ListPlansState extends State<ListPlans> {
|
|||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
fontWeight: FontWeight.bold))),
|
fontWeight: FontWeight.bold))),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('UserName',
|
label: Text('Traveller',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Color(0xFF9E9DBD),
|
color: Color(0xFF9E9DBD),
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Archivo",
|
||||||
|
|||||||
@ -162,8 +162,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
child: Image.network(
|
child: Image.network(
|
||||||
selectedOrg!['logo'],
|
selectedOrg!['logo'],
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 50,
|
height: 80,
|
||||||
fit: BoxFit.contain,
|
// fit: BoxFit.contain,
|
||||||
errorBuilder: (context, error, stackTrace) {
|
errorBuilder: (context, error, stackTrace) {
|
||||||
return const CircleAvatar(
|
return const CircleAvatar(
|
||||||
radius: 20,
|
radius: 20,
|
||||||
@ -253,23 +253,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.of(context).size.width * 0.05),
|
horizontal: MediaQuery.of(context).size.width * 0.05),
|
||||||
child: Column(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
userData?["name"] ?? "N/A",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontFamily: "Archivo",
|
|
||||||
// color: Color(0xFF12B24B),
|
|
||||||
color: layoutColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 1,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
children: [
|
||||||
// if (userData?["role"] != "User")
|
// if (userData?["role"] != "User")
|
||||||
Builder(
|
Builder(
|
||||||
@ -320,19 +304,54 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
.toList()
|
.toList()
|
||||||
: menuItems;
|
: menuItems;
|
||||||
|
|
||||||
return filteredItems.map(buildMenuItem).toList();
|
// Create a new list starting with role display and divider
|
||||||
|
return [
|
||||||
|
PopupMenuItem<String>(
|
||||||
|
enabled: false, // ❌ Not clickable
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
userData?["role"] ?? '',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(), // 👈 Divider after role
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...filteredItems
|
||||||
|
.map(buildMenuItem)
|
||||||
|
.toList(), // 👈 then normal items
|
||||||
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// itemBuilder: (BuildContext context) {
|
||||||
|
// final isUser = userData?["role"] == "User";
|
||||||
|
// final filteredItems = isUser
|
||||||
|
// ? menuItems
|
||||||
|
// .where((item) =>
|
||||||
|
// item['value'] == '/CreateUserDetails' ||
|
||||||
|
// item['value'] == '/logout')
|
||||||
|
// .toList()
|
||||||
|
// : menuItems;
|
||||||
|
//
|
||||||
|
// return filteredItems.map(buildMenuItem).toList();
|
||||||
|
// },
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
cursor: SystemMouseCursors.click,
|
cursor: SystemMouseCursors.click,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
userData?["role"] ?? "Role",
|
userData?["name"] ?? "N/A",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w300,
|
fontWeight: FontWeight.w500,
|
||||||
fontFamily: "Archivo",
|
fontFamily: "Roboto",
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -349,8 +368,6 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
bottom: PreferredSize(
|
bottom: PreferredSize(
|
||||||
|
|||||||
@ -451,7 +451,9 @@ class ApiService {
|
|||||||
// Flight From - To
|
// Flight From - To
|
||||||
|
|
||||||
Future<List<dynamic>> fetchFlightsCountryList() async {
|
Future<List<dynamic>> fetchFlightsCountryList() async {
|
||||||
final String apiUrldata = '$apiUrl/api/getAirportCodeMaster';
|
final String apiUrldata =
|
||||||
|
'$apiUrl/api/getAirportCodeMaster?limit=1000&offset=0';
|
||||||
|
|
||||||
final token = await getToken();
|
final token = await getToken();
|
||||||
|
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user