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';
|
||||
|
||||
class FlightScreen extends StatefulWidget {
|
||||
final bool hasAction;
|
||||
final String? tripType;
|
||||
final List<Map<String, dynamic>> flightData;
|
||||
final Map<String, dynamic>? apiData;
|
||||
final Map<String, dynamic>? apiDataForClass;
|
||||
final String? loginUser;
|
||||
final Function(bool) onClose;
|
||||
final Function(Map<String, dynamic>) onSaveFlight;
|
||||
@ -22,7 +25,10 @@ class FlightScreen extends StatefulWidget {
|
||||
required this.onClose,
|
||||
required this.onSaveFlight,
|
||||
required this.selectedItem,
|
||||
required this.flightData});
|
||||
required this.flightData,
|
||||
required this.hasAction,
|
||||
this.tripType,
|
||||
this.apiDataForClass});
|
||||
|
||||
@override
|
||||
_FlightScreenState createState() => _FlightScreenState();
|
||||
@ -32,6 +38,10 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
ApiService apiService = ApiService();
|
||||
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?> flightLastTripDateNotifier;
|
||||
|
||||
@ -42,6 +52,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
|
||||
String? selectedTripType;
|
||||
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;
|
||||
int multiTripRowCount = 1;
|
||||
|
||||
@ -66,7 +78,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
List<TextEditingController> controllers = []; // Dynamic controllers
|
||||
|
||||
Map<String, String> errorMessages = {};
|
||||
|
||||
// forex_pre_paid_card_number
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -120,7 +132,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
textControllers["_time${i}Controller"]
|
||||
?.addListener(() => _clearError("time_$i"));
|
||||
}
|
||||
// loadCountryList();
|
||||
loadCountryList();
|
||||
|
||||
flightFirstTripDateNotifier = 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 {
|
||||
setState(() {
|
||||
isCountryLoading = true;
|
||||
});
|
||||
|
||||
final result = await apiService.fetchFlightsCountryList();
|
||||
|
||||
if (result is List) {
|
||||
countryList =
|
||||
result.map((item) => Map<String, dynamic>.from(item)).toList();
|
||||
} else {
|
||||
countryList = []; // fallback or throw error
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
int getRowCount() {
|
||||
@ -285,8 +339,12 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
for (int i = 1; i <= rowCount; i++) {
|
||||
final trip = {
|
||||
"class": selectedClasses[i],
|
||||
"from_place": textControllers["_from${i}Controller"]?.text ?? "",
|
||||
"to_place": textControllers["_to${i}Controller"]?.text ?? "",
|
||||
// "from_place": countryMap[selectedFrom[i]],
|
||||
"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 ?? "",
|
||||
"time": textControllers["_time${i}Controller"]?.text ?? "",
|
||||
"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
|
||||
|
||||
selectedClasses[index] = trip["class"].toString();
|
||||
textControllers["_from${index}Controller"] =
|
||||
TextEditingController(text: trip["from_place"]);
|
||||
textControllers["_to${index}Controller"] =
|
||||
TextEditingController(text: trip["to_place"]);
|
||||
selectedFrom[index] = trip["from_place"].toString();
|
||||
selectedTo[index] = trip["to_place"].toString();
|
||||
// textControllers["_from${index}Controller"] =
|
||||
// TextEditingController(text: trip["from_place"]);
|
||||
// textControllers["_to${index}Controller"] =
|
||||
// TextEditingController(text: trip["to_place"]);
|
||||
textControllers["_date${index}Controller"] =
|
||||
TextEditingController(text: trip["date"]);
|
||||
textControllers["_time${index}Controller"] =
|
||||
@ -430,12 +490,19 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
|
||||
// Loop through each trip row and validate required fields
|
||||
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";
|
||||
}
|
||||
if (textControllers["_to${i}Controller"]?.text.trim().isEmpty ?? true) {
|
||||
if (selectedTo[i] == null) {
|
||||
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) {
|
||||
errorMessages["date_$i"] = "Required";
|
||||
}
|
||||
@ -468,8 +535,8 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
int newIndex = 1;
|
||||
for (int i = 1; i <= multiTripRowCount + 1; i++) {
|
||||
if (i == index) continue; // Skip the deleted one
|
||||
updatedTextControllers["_from${newIndex}Controller"] =
|
||||
textControllers["_from${i}Controller"]!;
|
||||
// updatedTextControllers["_from${newIndex}Controller"] =
|
||||
// textControllers["_from${i}Controller"]!;
|
||||
updatedTextControllers["_to${newIndex}Controller"] =
|
||||
textControllers["_to${i}Controller"]!;
|
||||
updatedTextControllers["_date${newIndex}Controller"] =
|
||||
@ -491,6 +558,27 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
}
|
||||
|
||||
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("Updated Trips: $multiTripRowCount");
|
||||
print("Updated Classes: $selectedClasses");
|
||||
@ -916,7 +1004,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
}
|
||||
|
||||
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
|
||||
.map((item) => DropdownMenuItem<String>(
|
||||
@ -1020,18 +1108,18 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
late Map<String, String> countryMap; // Mapping country_code -> country_name
|
||||
late List<String> countryCodes; // List of country codes
|
||||
// late Map<String, String> countryMap; // Mapping country_code -> country_name
|
||||
// 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 = {
|
||||
for (var item in countryList)
|
||||
item['country_code'] as String: item['country_name'] as String
|
||||
};
|
||||
|
||||
// Extract only country codes for processing
|
||||
countryCodes = countryMap.keys.toList();
|
||||
|
||||
selectedCountry ??= null;
|
||||
// // Extract only country codes for processing
|
||||
// countryCodes = countryMap.keys.toList();
|
||||
//
|
||||
// selectedCountry ??= null;
|
||||
|
||||
return [
|
||||
Column(
|
||||
@ -1053,28 +1141,31 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
// : MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: DropdownButtonFormField<String>(
|
||||
focusNode: focusNodes["_class${index}FocusNode"],
|
||||
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||
// controller: _hotelNameController,
|
||||
value: selectedClasses[index],
|
||||
style: TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||
),
|
||||
onChanged: purposeList.isNotEmpty
|
||||
? (newValue) {
|
||||
setState(() {
|
||||
selectedClasses[index] = newValue;
|
||||
});
|
||||
child: isCountryLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: DropdownButtonFormField<String>(
|
||||
focusNode: focusNodes["_class${index}FocusNode"],
|
||||
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
||||
// controller: _hotelNameController,
|
||||
value: selectedClasses[index],
|
||||
|
||||
print(selectedClasses[index]);
|
||||
}
|
||||
: null,
|
||||
items: dropdownItems,
|
||||
),
|
||||
style: TextStyle(fontSize: 12),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10), // Proper padding
|
||||
),
|
||||
onChanged: purposeList.isNotEmpty
|
||||
? (newValue) {
|
||||
setState(() {
|
||||
selectedClasses[index] = newValue;
|
||||
});
|
||||
|
||||
print(selectedClasses[index]);
|
||||
}
|
||||
: null,
|
||||
items: dropdownItems,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -1099,72 +1190,75 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
// isFocused: _fromFocus,
|
||||
isFocused: focusStates["_from${index}Focused"] ?? false,
|
||||
// isFocused: focusStates["_from${fieldIndex}Focused"] ?? false,
|
||||
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");
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
// )
|
||||
// isFocused: _fromFocus,
|
||||
isFocused: focusStates["_from${index}Focused"] ?? false,
|
||||
// isFocused: focusStates["_from${fieldIndex}Focused"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: isCountryLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: DropdownSearch<String>(
|
||||
selectedItem: selectedFrom[index] != null
|
||||
? countryMap[selectedFrom[index]]
|
||||
: 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,
|
||||
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;
|
||||
|
||||
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),
|
||||
),
|
||||
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) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
@ -1192,24 +1286,51 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: focusStates["_to${index}Focused"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
focusNode: focusNodes["_to${index}FocusNode"],
|
||||
controller: textControllers["_to${index}Controller"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "To",
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
isFocused: focusStates["_to${index}Focused"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: isCountryLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: DropdownSearch<String>(
|
||||
selectedItem: selectedTo[index] != null
|
||||
? countryMap[selectedTo[index]]
|
||||
: 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,
|
||||
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) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
@ -1293,7 +1414,7 @@ class _FlightScreenState extends State<FlightScreen> {
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: focusStates["_timeFocused"] ?? false,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.08 : null,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
import 'package:dropdown_search/dropdown_search.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
|
||||
import '../../services/apiService.dart';
|
||||
import '../../widgets/custom_text_field.dart';
|
||||
import '../../widgets/custom_text_itnerary_sub.dart';
|
||||
|
||||
class TrainScreen extends StatefulWidget {
|
||||
final Map<String, dynamic>? apiData;
|
||||
final Map<String, dynamic>? apiDataForClass;
|
||||
final Function(Map<String, dynamic>) onSavetrain;
|
||||
final Function(bool) onClose;
|
||||
final Map<String, dynamic>? selectedItem;
|
||||
@ -17,7 +20,8 @@ class TrainScreen extends StatefulWidget {
|
||||
this.apiData,
|
||||
required this.onSavetrain,
|
||||
required this.selectedItem,
|
||||
required this.loginUser});
|
||||
required this.loginUser,
|
||||
this.apiDataForClass});
|
||||
|
||||
@override
|
||||
_TrainScreenState createState() => _TrainScreenState();
|
||||
@ -26,6 +30,12 @@ class TrainScreen extends StatefulWidget {
|
||||
class _TrainScreenState extends State<TrainScreen> {
|
||||
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 = {};
|
||||
|
||||
final FocusNode _trainNoFocusNode = FocusNode();
|
||||
@ -53,6 +63,8 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
bool _commentsFocus = false;
|
||||
|
||||
String? selectedClass;
|
||||
String? selectedFrom;
|
||||
String? selectedTo;
|
||||
|
||||
Map<String, String> errorMessages = {};
|
||||
|
||||
@ -60,8 +72,10 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
Map<String, dynamic> data = {
|
||||
"train_no": _trainNoController.text,
|
||||
"class": selectedClass,
|
||||
"from_station": _fromController.text,
|
||||
"to_station": _toController.text,
|
||||
"from_station": selectedFrom,
|
||||
// "from_station": _fromController.text,
|
||||
"to_station": selectedTo,
|
||||
// "to_station": _toController.text,
|
||||
"date": _dateController.text,
|
||||
"time": _timeController.text,
|
||||
"comments": _trainCommentsController.text,
|
||||
@ -128,7 +142,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
|
||||
_trainCommentsController = initController("comments");
|
||||
_trainNoController = initController("train_no");
|
||||
_fromController = initController("from_station");
|
||||
// _fromController = initController("from_station");
|
||||
_toController = initController("to_station");
|
||||
_dateController = initController("date");
|
||||
_timeController = initController("time");
|
||||
@ -138,11 +152,50 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
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"));
|
||||
_fromController.addListener(() => _clearError("from_station"));
|
||||
// _fromController.addListener(() => _clearError("from_station"));
|
||||
_toController.addListener(() => _clearError("to_station"));
|
||||
_dateController.addListener(() => _clearError("date"));
|
||||
_timeController.addListener(() => _clearError("time"));
|
||||
|
||||
loadCountryList();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -189,6 +242,32 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
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() {
|
||||
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
|
||||
.map((item) => DropdownMenuItem<String>(
|
||||
@ -504,24 +583,84 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: _fromFocus,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
focusNode: _fromFocusNode,
|
||||
controller: _fromController,
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "From",
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
isFocused: _fromFocus,
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: isCountryLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: DropdownSearch<String>(
|
||||
// selectedItem: selectedFrom != null
|
||||
// ? countryMap[selectedFrom]
|
||||
// : null,
|
||||
|
||||
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,
|
||||
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) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
@ -553,18 +692,45 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
isDesktop: isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
focusNode: _toFocusNode,
|
||||
controller: _toController,
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "To",
|
||||
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
child: isCountryLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: DropdownSearch<String>(
|
||||
selectedItem: selectedTo != null
|
||||
? countryMap[
|
||||
selectedTo] // 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,
|
||||
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) ...[
|
||||
@ -649,7 +815,7 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
isFocused: _timeFocus,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.08 : null,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
|
||||
@ -1,28 +1,106 @@
|
||||
import 'package:flutter/material.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 Function(bool, Map<String, dynamic>, String) onOpen;
|
||||
final Function(Map<String, dynamic>) onDeleteFlight;
|
||||
final Map<String, dynamic>? apiData;
|
||||
|
||||
final Function(String, bool) onAddNew;
|
||||
final bool isViewMode;
|
||||
|
||||
const FlightListWidget(
|
||||
{super.key,
|
||||
required this.flightList,
|
||||
required this.onOpen,
|
||||
required this.onDeleteFlight,
|
||||
required this.onAddNew,
|
||||
required this.apiData,
|
||||
required this.isViewMode});
|
||||
const FlightListWidget({
|
||||
Key? key,
|
||||
required this.flightList,
|
||||
required this.onOpen,
|
||||
required this.onDeleteFlight,
|
||||
required this.onAddNew,
|
||||
required this.apiData,
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
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(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Container(
|
||||
@ -39,15 +117,15 @@ class FlightListWidget extends StatelessWidget {
|
||||
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
cursor: widget.isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: isViewMode
|
||||
onTap: widget.isViewMode
|
||||
? null
|
||||
: () {
|
||||
checkClass();
|
||||
print("New data");
|
||||
onAddNew("Flight", true);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
@ -81,10 +159,10 @@ class FlightListWidget extends StatelessWidget {
|
||||
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
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");
|
||||
|
||||
List<dynamic> visatypeList = apiData?['flight_class'] ?? [];
|
||||
List<dynamic> visatypeList = widget.apiData?['flight_class'] ?? [];
|
||||
|
||||
String getRequestForClass(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
@ -174,13 +252,13 @@ class FlightListWidget extends StatelessWidget {
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Flight"),
|
||||
onTap: () => widget.onOpen(true, item, "Flight"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteFlight(item),
|
||||
onTap: () => widget.onDeleteFlight(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
@ -224,6 +302,13 @@ class FlightListWidget extends StatelessWidget {
|
||||
if (isDesktop)
|
||||
if (item["trips"] != null && item["trips"].isNotEmpty)
|
||||
...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(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Row(
|
||||
@ -240,7 +325,8 @@ class FlightListWidget extends StatelessWidget {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
||||
"$fromPlaceCountry (from) - (to) $toPlaceCountry",
|
||||
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import 'package:flutter/material.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 Function(bool, Map<String, dynamic>, String) onOpen;
|
||||
final Function(Map<String, dynamic>) onDeleteTrain;
|
||||
@ -10,14 +14,83 @@ class TrainListWidget extends StatelessWidget {
|
||||
final Map<String, dynamic>? apiData;
|
||||
|
||||
const TrainListWidget({
|
||||
super.key,
|
||||
Key? key,
|
||||
required this.trainList,
|
||||
required this.onOpen,
|
||||
required this.onDeleteTrain,
|
||||
required this.onAddNew,
|
||||
required this.isViewMode,
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
@ -35,20 +108,20 @@ class TrainListWidget extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MouseRegion(
|
||||
cursor: isViewMode
|
||||
cursor: widget.isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
child: MouseRegion(
|
||||
cursor: isViewMode
|
||||
cursor: widget.isViewMode
|
||||
? SystemMouseCursors.forbidden
|
||||
: SystemMouseCursors.click,
|
||||
|
||||
child: GestureDetector(
|
||||
onTap: isViewMode
|
||||
onTap: widget.isViewMode
|
||||
? null
|
||||
: () {
|
||||
print("New data");
|
||||
onAddNew("Train", true);
|
||||
checkClass();
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
@ -130,10 +203,10 @@ class TrainListWidget extends StatelessWidget {
|
||||
|
||||
Widget _buildData(BuildContext context, bool isDesktop) {
|
||||
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");
|
||||
|
||||
List<dynamic> trainClassList = apiData?['train_class'] ?? [];
|
||||
List<dynamic> trainClassList = widget.apiData?['train_class'] ?? [];
|
||||
|
||||
String getRequestForTrainClass(String? specialRequestKey) {
|
||||
if (specialRequestKey == null) return "N/A";
|
||||
@ -180,6 +253,11 @@ class TrainListWidget extends StatelessWidget {
|
||||
itemBuilder: (context, 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(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
@ -217,13 +295,13 @@ class TrainListWidget extends StatelessWidget {
|
||||
),
|
||||
Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () => onOpen(true, item, "Train"),
|
||||
onTap: () => widget.onOpen(true, item, "Train"),
|
||||
child: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
GestureDetector(
|
||||
onTap: () => onDeleteTrain(item),
|
||||
onTap: () => widget.onDeleteTrain(item),
|
||||
child: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
),
|
||||
@ -284,7 +362,9 @@ class TrainListWidget extends StatelessWidget {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
"${item["from_station"]!} - ${(item["to_station"])}",
|
||||
"$fromPlaceCountry (from) - (to) $toPlaceCountry",
|
||||
|
||||
// "${item["from_station"]!} - ${(item["to_station"])}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@ -284,6 +284,9 @@ class CreateNewPlan extends StatefulWidget {
|
||||
}
|
||||
|
||||
class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
final GlobalKey<DynamicItineraryState> dynamicItineraryKey =
|
||||
GlobalKey<DynamicItineraryState>();
|
||||
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
final TextEditingController _tripTitleController = TextEditingController();
|
||||
@ -311,12 +314,14 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
late Color layoutColorForUser;
|
||||
|
||||
Map<String, dynamic>? apiData; // Store API response here
|
||||
Map<String, dynamic>? apiDataForClass; // Store API response here
|
||||
List<dynamic>? apiCountryData;
|
||||
List<dynamic>? apiCostData; // Store API response here
|
||||
bool isLoading = true; // Track loading state
|
||||
String? TripPlanAction;
|
||||
bool showDomestic = false;
|
||||
bool showInternational = false;
|
||||
bool hasAction = true;
|
||||
|
||||
late Map<String, String> costCenterMap;
|
||||
List<String> costCenterIds = [];
|
||||
@ -511,6 +516,12 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
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') &&
|
||||
widget.selectedPlanData['plan_id'] != null) {
|
||||
print("Plan ID exists: ${widget.selectedPlanData['plan_id']}");
|
||||
@ -528,15 +539,19 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
if (TripPlanAction == "Plan Creation Not Allowed") {
|
||||
showDomestic = false;
|
||||
showInternational = false;
|
||||
hasAction = false;
|
||||
} else if (TripPlanAction == "Only Domestic Plan Creation Allowed") {
|
||||
showDomestic = true;
|
||||
showInternational = false;
|
||||
hasAction = true;
|
||||
} else if (TripPlanAction == "Only International Plan Creation Allowed") {
|
||||
showDomestic = false;
|
||||
showInternational = true;
|
||||
hasAction = true;
|
||||
} else if (TripPlanAction == "Both Type Plan Creation Allowed") {
|
||||
showDomestic = 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
|
||||
|
||||
bool validateForm() {
|
||||
@ -1213,7 +1277,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: DynamicItinerary(
|
||||
key: dynamicItineraryKey,
|
||||
hasAction: hasAction,
|
||||
tripType: _selectedTripType,
|
||||
apiData: apiData,
|
||||
apiDataForClass: apiDataForClass,
|
||||
apiCountryData: apiCountryData,
|
||||
onItineraryUpdate: handleItineraryUpdate,
|
||||
loginUser: selfId,
|
||||
@ -1588,7 +1656,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Purpose of Travel *", // Your label
|
||||
"Purpose of Trip *", // Your label
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -1887,6 +1955,9 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
: () {
|
||||
setState(() {
|
||||
_selectedTripType = "1";
|
||||
fetchTrainFlightClass(1);
|
||||
|
||||
dynamicItineraryKey.currentState?.updateSelectedServices();
|
||||
});
|
||||
},
|
||||
child: CustomTextFieldWrapper(
|
||||
@ -1944,6 +2015,8 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
: () {
|
||||
setState(() {
|
||||
_selectedTripType = "2";
|
||||
fetchTrainFlightClass(2);
|
||||
dynamicItineraryKey.currentState?.updateSelectedServices();
|
||||
});
|
||||
},
|
||||
child: CustomTextFieldWrapper(
|
||||
|
||||
@ -25,7 +25,10 @@ import '../itnerary_list/miscellaneous_list.dart';
|
||||
import '../itnerary_list/visa_list.dart';
|
||||
|
||||
class DynamicItinerary extends StatefulWidget {
|
||||
final bool hasAction;
|
||||
final String? tripType;
|
||||
final Map<String, dynamic>? apiData;
|
||||
final Map<String, dynamic>? apiDataForClass;
|
||||
final List<dynamic>? apiCountryData;
|
||||
final String? loginUser;
|
||||
final Function(String, List<Map<String, dynamic>>)
|
||||
@ -40,15 +43,19 @@ class DynamicItinerary extends StatefulWidget {
|
||||
required this.apiCountryData,
|
||||
required this.loginUser,
|
||||
required this.selectedPlanData,
|
||||
required this.isViewMode});
|
||||
required this.isViewMode,
|
||||
required this.hasAction,
|
||||
this.tripType,
|
||||
this.apiDataForClass});
|
||||
|
||||
@override
|
||||
_DynamicItineraryState createState() => _DynamicItineraryState();
|
||||
DynamicItineraryState createState() => DynamicItineraryState();
|
||||
}
|
||||
|
||||
class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
class DynamicItineraryState extends State<DynamicItinerary> {
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
String? _tripType;
|
||||
String selectedOption = "";
|
||||
String selectedListOption = "";
|
||||
|
||||
@ -80,6 +87,25 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
super.initState();
|
||||
handleSelectedPlan();
|
||||
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 {
|
||||
@ -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 {
|
||||
await loadAllServices();
|
||||
await loadOrgSelectedAlServices();
|
||||
|
||||
final allowedServiceNames = getAllowedServiceNames();
|
||||
|
||||
if (hasAnyItineraryData()) {
|
||||
print("SELCTSplanChhose: ${filledItineraryKeys}");
|
||||
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);
|
||||
final isNameAllowed =
|
||||
allowedServiceNames.isEmpty || allowedServiceNames.contains(name);
|
||||
return filledItineraryKeys.contains(name) &&
|
||||
!selectedIds.contains(id) &&
|
||||
isNameAllowed;
|
||||
}).toList();
|
||||
|
||||
final originalFiltered = selectedAllServices!
|
||||
.where((service) =>
|
||||
selectedIds.contains(service['service_id'].toString()))
|
||||
.toList();
|
||||
final originalFiltered = selectedAllServices!.where((service) {
|
||||
final name = (service['name'] ?? "").toString().toLowerCase();
|
||||
final id = service['service_id'].toString();
|
||||
final isNameAllowed =
|
||||
allowedServiceNames.isEmpty || allowedServiceNames.contains(name);
|
||||
return selectedIds.contains(id) && isNameAllowed;
|
||||
}).toList();
|
||||
|
||||
// setState(() {
|
||||
// ServicesChoosed = [...originalFiltered, ...additionalServices];
|
||||
// });
|
||||
setState(() {
|
||||
ServicesChoosed = [...originalFiltered, ...additionalServices]
|
||||
..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
||||
@ -162,21 +265,20 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
final selectedIds =
|
||||
selectedOrgServiceIds.map((e) => e['service_id']).toSet();
|
||||
|
||||
final filtered = selectedAllServices!
|
||||
.where((service) =>
|
||||
selectedIds.contains(service['service_id'].toString()))
|
||||
.toList();
|
||||
final filtered = selectedAllServices!.where((service) {
|
||||
final name = (service['name'] ?? "").toString().toLowerCase();
|
||||
final isNameAllowed =
|
||||
allowedServiceNames.isEmpty || allowedServiceNames.contains(name);
|
||||
return selectedIds.contains(service['service_id'].toString()) &&
|
||||
isNameAllowed;
|
||||
}).toList();
|
||||
|
||||
setState(() {
|
||||
ServicesChoosed = filtered
|
||||
..sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
|
||||
});
|
||||
|
||||
// setState(() {
|
||||
// ServicesChoosed = filtered;
|
||||
// });
|
||||
|
||||
print("Filtered Selected Services Chooesed: $ServicesChoosed");
|
||||
print("Filtered Selected Services Chosen: $ServicesChoosed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,6 +510,8 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
switch (selectedListOption) {
|
||||
case "Train":
|
||||
selectedListWidget = TrainListWidget(
|
||||
hasAction: widget.hasAction,
|
||||
tripType: widget.tripType,
|
||||
trainList: itineraryData["Train"]!,
|
||||
onOpen: handleEdit,
|
||||
onAddNew: handlecreateNewPlan,
|
||||
@ -491,6 +595,8 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
case "Flight":
|
||||
default:
|
||||
selectedListWidget = FlightListWidget(
|
||||
hasAction: widget.hasAction,
|
||||
tripType: widget.tripType,
|
||||
flightList: itineraryData["Flight"]!,
|
||||
onOpen: handleEdit,
|
||||
onAddNew: handlecreateNewPlan,
|
||||
@ -505,6 +611,7 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
selectedWidget = TrainScreen(
|
||||
onClose: handleClose,
|
||||
apiData: widget.apiData,
|
||||
apiDataForClass: widget.apiDataForClass,
|
||||
loginUser: widget.loginUser,
|
||||
onSavetrain: (data) => handleItineraryUpdate("Train", data),
|
||||
selectedItem: selectedItem);
|
||||
@ -582,10 +689,13 @@ class _DynamicItineraryState extends State<DynamicItinerary> {
|
||||
case "Flight":
|
||||
default:
|
||||
selectedWidget = FlightScreen(
|
||||
hasAction: widget.hasAction,
|
||||
tripType: widget.tripType,
|
||||
onClose: handleClose,
|
||||
loginUser: widget.loginUser,
|
||||
onSaveFlight: (data) => handleItineraryUpdate("Flight", data),
|
||||
apiData: widget.apiData,
|
||||
apiDataForClass: widget.apiDataForClass,
|
||||
selectedItem: selectedItem,
|
||||
flightData: itineraryData["Flight"]!,
|
||||
);
|
||||
|
||||
@ -36,6 +36,10 @@ class _ListPlansState extends State<ListPlans> {
|
||||
Color? layoutColor;
|
||||
Color? bodyColor;
|
||||
|
||||
List<Plan> allPlans = [];
|
||||
List<Plan> filteredPlans = [];
|
||||
TextEditingController searchController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -44,11 +48,33 @@ class _ListPlansState extends State<ListPlans> {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
initializeData();
|
||||
loadInitialData();
|
||||
|
||||
futurePlans.then((plans) {
|
||||
setState(() {
|
||||
allPlans = plans;
|
||||
filteredPlans = plans;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 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 {
|
||||
String? layoutString = await getLayoutColor();
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
@ -322,7 +348,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('Plans List',
|
||||
const Text('Trip List',
|
||||
style: TextStyle(
|
||||
fontFamily: "Archivo",
|
||||
fontSize: 16,
|
||||
@ -334,9 +360,9 @@ class _ListPlansState extends State<ListPlans> {
|
||||
Spacer(),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
// or use Flexible
|
||||
child: TextField(
|
||||
onChanged: (query) {},
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search for a plan",
|
||||
hintStyle:
|
||||
@ -351,7 +377,6 @@ class _ListPlansState extends State<ListPlans> {
|
||||
color: Colors.grey.shade300, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
borderSide:
|
||||
BorderSide(color: Colors.blueAccent, width: 1),
|
||||
),
|
||||
@ -510,7 +535,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
),
|
||||
columns: const [
|
||||
DataColumn(
|
||||
label: Text('Plan Id',
|
||||
label: Text('Trip Id',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF9E9DBD),
|
||||
fontSize: 14,
|
||||
@ -523,7 +548,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
fontFamily: "Archivo",
|
||||
fontWeight: FontWeight.bold))),
|
||||
DataColumn(
|
||||
label: Text('UserName',
|
||||
label: Text('Traveller',
|
||||
style: TextStyle(
|
||||
color: Color(0xFF9E9DBD),
|
||||
fontFamily: "Archivo",
|
||||
|
||||
@ -162,8 +162,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
||||
child: Image.network(
|
||||
selectedOrg!['logo'],
|
||||
width: 100,
|
||||
height: 50,
|
||||
fit: BoxFit.contain,
|
||||
height: 80,
|
||||
// fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return const CircleAvatar(
|
||||
radius: 20,
|
||||
@ -253,102 +253,119 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width * 0.05),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
child: Row(
|
||||
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: [
|
||||
// if (userData?["role"] != "User")
|
||||
Builder(
|
||||
builder: (context) => PopupMenuButton<String>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
// icon: const Icon(Icons.arrow_drop_down,
|
||||
// size: 20, color: Colors.black87),
|
||||
offset: const Offset(0, 50), // 👈 shift it 50 pixels down
|
||||
onSelected: (String value) {
|
||||
switch (value) {
|
||||
case '/OrganizationSetup':
|
||||
context.go('/OrganizationSetup');
|
||||
break;
|
||||
case '/listUser':
|
||||
context.go('/listUser');
|
||||
break;
|
||||
case '/group':
|
||||
context.go('/group');
|
||||
break;
|
||||
case '/PolicyList':
|
||||
context.go('/PolicyList');
|
||||
case '/CreateUserDetails':
|
||||
context.go(
|
||||
"/CreateUserDetails",
|
||||
extra: {
|
||||
"selectedUser": userDetails,
|
||||
"isEditProfile": true,
|
||||
"isViewMode": true
|
||||
},
|
||||
);
|
||||
case '/logout':
|
||||
context.go('/');
|
||||
break;
|
||||
}
|
||||
},
|
||||
// if (userData?["role"] != "User")
|
||||
Builder(
|
||||
builder: (context) => PopupMenuButton<String>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
// icon: const Icon(Icons.arrow_drop_down,
|
||||
// size: 20, color: Colors.black87),
|
||||
offset: const Offset(0, 50), // 👈 shift it 50 pixels down
|
||||
onSelected: (String value) {
|
||||
switch (value) {
|
||||
case '/OrganizationSetup':
|
||||
context.go('/OrganizationSetup');
|
||||
break;
|
||||
case '/listUser':
|
||||
context.go('/listUser');
|
||||
break;
|
||||
case '/group':
|
||||
context.go('/group');
|
||||
break;
|
||||
case '/PolicyList':
|
||||
context.go('/PolicyList');
|
||||
case '/CreateUserDetails':
|
||||
context.go(
|
||||
"/CreateUserDetails",
|
||||
extra: {
|
||||
"selectedUser": userDetails,
|
||||
"isEditProfile": true,
|
||||
"isViewMode": true
|
||||
},
|
||||
);
|
||||
case '/logout':
|
||||
context.go('/');
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// itemBuilder: (BuildContext context) =>
|
||||
// menuItems.map(buildMenuItem).toList(),
|
||||
// itemBuilder: (BuildContext context) =>
|
||||
// menuItems.map(buildMenuItem).toList(),
|
||||
|
||||
itemBuilder: (BuildContext context) {
|
||||
final isUser = userData?["role"] == "User";
|
||||
final filteredItems = isUser
|
||||
? menuItems
|
||||
.where((item) =>
|
||||
item['value'] == '/CreateUserDetails' ||
|
||||
item['value'] == '/logout')
|
||||
.toList()
|
||||
: menuItems;
|
||||
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(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
// 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"] ?? "Role",
|
||||
userData?["role"] ?? '',
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w300,
|
||||
fontFamily: "Archivo",
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 20,
|
||||
color: Colors.black87,
|
||||
),
|
||||
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(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
userData?["name"] ?? "N/A",
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: "Roboto",
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 20,
|
||||
color: Colors.black87,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@ -451,7 +451,9 @@ class ApiService {
|
||||
// Flight From - To
|
||||
|
||||
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();
|
||||
|
||||
if (token == null) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user