559 lines
19 KiB
Dart
559 lines
19 KiB
Dart
import 'package:easy_stepper/easy_stepper.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:frontend/Screens/itnerary_list/accomodation_list.dart';
|
|
import 'package:frontend/Screens/itnerary_list/bus_list.dart';
|
|
import 'package:frontend/Screens/itnerary_list/flight_list.dart';
|
|
import 'package:frontend/Screens/itnerary_list/taxi_list.dart';
|
|
import 'package:frontend/Screens/itnerary_list/train_list.dart';
|
|
import 'package:responsive_builder/responsive_builder.dart';
|
|
|
|
import '../itnerary/accomodations.dart';
|
|
import '../itnerary/bus.dart';
|
|
import '../itnerary/flights.dart';
|
|
import '../itnerary/forex.dart';
|
|
import '../itnerary/insurance.dart';
|
|
import '../itnerary/miscellaneous.dart';
|
|
import '../itnerary/taxi.dart';
|
|
import '../itnerary/train.dart';
|
|
import '../itnerary/visa.dart';
|
|
import '../itnerary_list/forex_list.dart';
|
|
import '../itnerary_list/insurance_list.dart';
|
|
import '../itnerary_list/miscellaneous_list.dart';
|
|
import '../itnerary_list/visa_list.dart';
|
|
|
|
class DynamicItinerary extends StatefulWidget {
|
|
final Map<String, dynamic>? apiData;
|
|
final List<dynamic>? apiCountryData;
|
|
final String? loginUser;
|
|
final Function(String, List<Map<String, dynamic>>) onItineraryUpdate; // Updated Signature
|
|
final Map<String,dynamic> selectedPlanData;
|
|
final bool isViewMode ;
|
|
|
|
const DynamicItinerary({super.key, required this.apiData, required this.onItineraryUpdate,
|
|
required this.apiCountryData, required this.loginUser,required this.selectedPlanData, required this.isViewMode});
|
|
|
|
|
|
@override
|
|
_DynamicItineraryState createState() => _DynamicItineraryState();
|
|
}
|
|
|
|
class _DynamicItineraryState extends State<DynamicItinerary> {
|
|
|
|
String selectedOption = "";
|
|
String selectedListOption = "";
|
|
|
|
bool isSelected = false;
|
|
Map<String, dynamic>? selectedItem;
|
|
int? selectedIndex;
|
|
|
|
// List<Map<String, dynamic>> miscellaneousList = [];
|
|
|
|
Map<String, List<Map<String, dynamic>>> itineraryData = {
|
|
"Train": [],
|
|
"Bus": [],
|
|
"Taxi": [],
|
|
"Miscellaneous": [],
|
|
"Flight": [],
|
|
"Accomodation": [],
|
|
"Insurance": [],
|
|
"Visa": [],
|
|
"Forex": [],
|
|
};
|
|
|
|
|
|
// Store form values for each tab
|
|
final Map<String, Map<String, String>> formData = {
|
|
"Flight": {}, // Stores data for the Flight tab
|
|
"Train": {}, // Stores data for the Train tab
|
|
"Taxi": {}, // Stores data for the Car tab
|
|
"Bus": {}, // Stores data for the Bus tab
|
|
"Insurance": {}, // Stores data for the Bus tab
|
|
"Accomodation": {},// Stores data for the Accomodation tab
|
|
"Miscellaneous": {},
|
|
"Forex": {},
|
|
"Visa": {},
|
|
};
|
|
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
handleSelectedPlan();
|
|
}
|
|
|
|
void handleSelectedPlan(){
|
|
|
|
|
|
// Check if selectedPlanData has itinerary data
|
|
if (hasAnyItineraryData()) {
|
|
print("selectedPlanData HAS DATA");
|
|
|
|
setState(() {
|
|
itineraryData = {
|
|
"Train": List<Map<String, dynamic>>.from(widget.selectedPlanData['train'] ?? []),
|
|
"Bus": List<Map<String, dynamic>>.from(widget.selectedPlanData['bus'] ?? []),
|
|
"Taxi": List<Map<String, dynamic>>.from(widget.selectedPlanData['taxi'] ?? []),
|
|
"Miscellaneous": List<Map<String, dynamic>>.from(widget.selectedPlanData['miscellaneous'] ?? []),
|
|
"Flight": List<Map<String, dynamic>>.from(widget.selectedPlanData['flight'] ?? []),
|
|
"Accomodation": List<Map<String, dynamic>>.from(widget.selectedPlanData['accomodation'] ?? []),
|
|
"Insurance": List<Map<String, dynamic>>.from(widget.selectedPlanData['insurance'] ?? []),
|
|
"Visa": List<Map<String, dynamic>>.from(widget.selectedPlanData['visa'] ?? []),
|
|
"Forex": List<Map<String, dynamic>>.from(widget.selectedPlanData['forex'] ?? []),
|
|
};
|
|
});
|
|
}
|
|
else {
|
|
print("No itinerary data available");
|
|
}
|
|
}
|
|
|
|
bool hasAnyItineraryData() {
|
|
List<String> keys = [
|
|
"train", "bus", "taxi", "miscellaneous", "flight",
|
|
"accomodation", "insurance", "visa", "forex"
|
|
];
|
|
|
|
for (String key in keys) {
|
|
if (widget.selectedPlanData.containsKey(key) &&
|
|
widget.selectedPlanData[key] is List &&
|
|
(widget.selectedPlanData[key] as List).isNotEmpty) {
|
|
return true; // At least one list has data
|
|
}
|
|
}
|
|
return false; // No itinerary data available
|
|
}
|
|
|
|
|
|
void handleClose(bool value) {
|
|
setState(() {
|
|
selectedOption = "";
|
|
isSelected = value;
|
|
selectedIndex = null;
|
|
selectedItem = null;
|
|
});
|
|
|
|
}
|
|
|
|
|
|
void handleEdit(bool value,selectedItem, title) {
|
|
setState(() {
|
|
selectedOption = title;
|
|
isSelected = value;
|
|
this.selectedItem = selectedItem;
|
|
|
|
});
|
|
|
|
print(selectedItem);
|
|
}
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
Widget selectedWidget;
|
|
Widget selectedListWidget;
|
|
|
|
// void updateFormData(String tab, String key, String value) {
|
|
// setState(() {
|
|
// formData[tab]![key] = value; // Update the stored data
|
|
// });
|
|
// }
|
|
|
|
|
|
void updateFormData(String tab, String key, String value) {
|
|
setState(() {
|
|
if (!formData.containsKey(tab)) {
|
|
formData[tab] = {}; // Initialize if null
|
|
}
|
|
formData[tab]![key] = value; // Update the stored data
|
|
});
|
|
}
|
|
|
|
|
|
void handleItineraryUpdate(String type, Map<String, dynamic> newData) {
|
|
setState(() {
|
|
if (!itineraryData.containsKey(type)) {
|
|
itineraryData[type] = []; // Initialize if null
|
|
}
|
|
|
|
List<Map<String, dynamic>> itemList = itineraryData[type]!;
|
|
|
|
print("newData - $newData");
|
|
|
|
// int? existingId = newData["id"];
|
|
// String? existingId = newData["id"];
|
|
|
|
String? idKey = "${type.toLowerCase()}_id";
|
|
String? existingId = newData[idKey];
|
|
|
|
|
|
print("Looking for ID using key: $idKey, Found ID: $existingId");
|
|
|
|
int? existingIndex = newData["indx"];
|
|
print("existingIndex - $existingIndex, existingId - $existingId");
|
|
|
|
// CASE 2: Update using id if available
|
|
if (existingId != null && existingId != 0) {
|
|
// int itemId = itemList.indexWhere((item) => item["id"] == existingId);
|
|
int itemId = itemList.indexWhere((item) => item[idKey]?.toString() == existingId.toString());
|
|
|
|
if (itemId != -1) {
|
|
print(" Updating existing item with id: $existingId");
|
|
newData["is_active"] = "1";
|
|
itemList[itemId] = newData;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// CASE 1: Update if indx exists in list
|
|
if (existingIndex != null && existingIndex != 0) {
|
|
int itemIndex = itemList.indexWhere((item) => item["indx"] == existingIndex);
|
|
if (itemIndex != -1) {
|
|
print("Updating existing item with indx: $existingIndex");
|
|
newData["is_active"] = "1";
|
|
itemList[itemIndex] = newData; // Update the item
|
|
return;
|
|
}
|
|
}
|
|
// CASE 3: New Entry (Assign new indx)
|
|
print(" Creating new entry");
|
|
newData["indx"] = itemList.length + 1; // Assign a new indx
|
|
newData["is_active"] = "1";
|
|
itemList.add(newData);
|
|
|
|
print(" Updated $type List: ${itineraryData[type]}");
|
|
});
|
|
print( " onItineraryUpdate - $type - ${itineraryData[type]!} ");
|
|
widget.onItineraryUpdate(type, itineraryData[type]!); // Notify parent
|
|
}
|
|
|
|
void handleItinerarydelete(String type, Map<String, dynamic> data){
|
|
setState(() {
|
|
// if(!itineraryData.containsKey(type)){
|
|
// return;
|
|
// }
|
|
|
|
|
|
if (!itineraryData.containsKey(type)) {
|
|
itineraryData[type] = []; // Initialize if null
|
|
}
|
|
|
|
List<Map<String, dynamic>> itemList = itineraryData[type]!;
|
|
|
|
|
|
|
|
String? idKey = "${type.toLowerCase()}_id";
|
|
String? existingId = data[idKey];
|
|
// int? existingId = data["id"];
|
|
// String? existingId = data["id"];
|
|
int? existingIndex = data["indx"];
|
|
|
|
print("🗑️ Deleting item -> ID: $existingId, Index: $existingIndex");
|
|
|
|
// Delete by ID
|
|
if(existingId != null && existingId != 0){
|
|
// itemList.removeWhere((item) => item[idKey]?.toString() == existingId.toString());
|
|
|
|
for (var item in itemList) {
|
|
if (item[idKey]?.toString() == existingId.toString()) {
|
|
item["is_active"] = 0; // Soft delete
|
|
print("Updated is_active to 0 for ID: $existingId");
|
|
}
|
|
}
|
|
itineraryData[type] = List.from(itemList);
|
|
print("Deleted by ID: $existingId");
|
|
}
|
|
//Delete by Index
|
|
else if(existingIndex != null && existingId !=0){
|
|
itemList.removeWhere((item) => item["indx"] == existingIndex);
|
|
print("Deleted by ID: $existingIndex");
|
|
}
|
|
else{
|
|
print("No Valid Deletion");
|
|
}
|
|
|
|
itineraryData[type]= List.from(itemList);
|
|
});
|
|
print( " onItineraryUpdate - $type - ${itineraryData[type]!} ");
|
|
widget.onItineraryUpdate(type, itineraryData[type]!); // Notify parent
|
|
}
|
|
|
|
|
|
// void handleItineraryUpdate(String type, Map<String, dynamic> newData) {
|
|
// setState(() {
|
|
// if (!itineraryData.containsKey(type)) {
|
|
// itineraryData[type] = []; // Initialize if null
|
|
// }
|
|
//
|
|
// // Assign an index based on the current list length
|
|
// int newIndex = itineraryData[type]!.length + 1;
|
|
// newData["indx"] = newIndex; // Add an ID field
|
|
//
|
|
// itineraryData[type]!.add(newData); // Append new object
|
|
// });
|
|
//
|
|
// widget.onItineraryUpdate(type, itineraryData[type]!); // Notify parent
|
|
// print("Updated $type List: ${itineraryData[type]}");
|
|
// }
|
|
|
|
|
|
|
|
switch (selectedListOption) {
|
|
case "Train":
|
|
selectedListWidget = TrainListWidget( trainList : itineraryData["Train"]!,
|
|
onOpen: handleEdit,
|
|
onDeleteTrain: (data)=> handleItinerarydelete("Train", data),
|
|
);
|
|
break;
|
|
case "Taxi":
|
|
selectedListWidget = TaxiListWidget( taxiList : itineraryData["Taxi"]! ,
|
|
onOpen: handleEdit,
|
|
onDeleteTaxi: (data)=> handleItinerarydelete("Taxi", data),);
|
|
break;
|
|
case "Bus":
|
|
selectedListWidget = BusListWidget(busList : itineraryData["Bus"]!,
|
|
onOpen: handleEdit,
|
|
onDeleteBus: (data) => handleItinerarydelete("Bus", data),);
|
|
break;
|
|
case "Insurance":
|
|
selectedListWidget = InsuranceListWidget(insuranceList : itineraryData["Insurance"]!,
|
|
onOpen: handleEdit, apiData: widget.apiData,
|
|
onDeleteInsurance:(data) => handleItinerarydelete("Insurance", data),);
|
|
break;
|
|
case "Visa":
|
|
selectedListWidget = VisaListWidget(visaList : itineraryData["Visa"]!,
|
|
apiData: widget.apiData, apiCountryData : widget.apiCountryData,
|
|
onOpen: handleEdit,
|
|
onDeleteMiscellaneous: (data) => handleItinerarydelete("Visa", data),);
|
|
break;
|
|
case "Forex":
|
|
selectedListWidget = ForexListWidget(forexList: itineraryData["Forex"]!,
|
|
apiCountryData : widget.apiCountryData,
|
|
onOpen: handleEdit,
|
|
onDeleteForex: (data) => handleItinerarydelete("Forex", data),);
|
|
break;
|
|
case "Accomodation":
|
|
selectedListWidget = AccomodationListWidget(accommodationList: itineraryData["Accomodation"]!,
|
|
onOpen: handleEdit,
|
|
onDeleteAccommodation:(data) => handleItinerarydelete("Accomodation", data));
|
|
break;
|
|
case "Miscellaneous":
|
|
selectedListWidget = MiscellaneousListWidget(miscellaneousList: itineraryData["Miscellaneous"]!,
|
|
onOpen: handleEdit,apiData: widget.apiData,
|
|
onDeleteMiscellaneous: (data) => handleItinerarydelete("Miscellaneous", data),
|
|
);
|
|
break;
|
|
case "Flight":
|
|
default:
|
|
selectedListWidget = FlightListWidget(flightList : itineraryData["Flight"]!,
|
|
onOpen: handleEdit,
|
|
onDeleteFlight: (data) => handleItinerarydelete("Flight", data)
|
|
|
|
);
|
|
break;
|
|
}
|
|
|
|
switch (selectedOption) {
|
|
case "Train":
|
|
selectedWidget = TrainScreen(onClose: handleClose, apiData: widget.apiData, loginUser : widget.loginUser,
|
|
onSavetrain :(data) => handleItineraryUpdate("Train", data),
|
|
selectedItem: selectedItem);
|
|
break;
|
|
case "Taxi":
|
|
selectedWidget = TaxiScreen(onClose: handleClose,apiData: widget.apiData, loginUser : widget.loginUser,
|
|
onSavetaxi: (data)=> handleItineraryUpdate("Taxi", data),
|
|
selectedItem: selectedItem);
|
|
break;
|
|
case "Bus":
|
|
selectedWidget = BusScreen(onClose: handleClose, apiData: widget.apiData, loginUser : widget.loginUser,
|
|
onSaveBus: (data)=> handleItineraryUpdate("Bus", data),
|
|
selectedItem: selectedItem);
|
|
break;
|
|
case "Insurance":
|
|
selectedWidget = InsuranceScreen(onClose: handleClose, apiData: widget.apiData, loginUser : widget.loginUser,
|
|
onSaveInsurance:(data) => handleItineraryUpdate("Insurance", data),
|
|
selectedItem: selectedItem);
|
|
break;
|
|
|
|
case "Visa":
|
|
selectedWidget = VisaScreen(onClose: handleClose,apiData: widget.apiData, apiCountryData : widget.apiCountryData, loginUser : widget.loginUser,
|
|
onSaveVisa: (data) => handleItineraryUpdate("Visa", data),
|
|
selectedItem: selectedItem,);
|
|
break;
|
|
case "Miscellaneous":
|
|
selectedWidget = MiscellaneousScreen(onClose: handleClose, apiData: widget.apiData, loginUser : widget.loginUser,
|
|
onSaveMiscellaneous: (data) => handleItineraryUpdate("Miscellaneous", data),
|
|
selectedItem: selectedItem, selectedIndex: selectedIndex, );
|
|
break;
|
|
case "Accomodation":
|
|
selectedWidget = AccomodationScreen( onClose: handleClose, loginUser : widget.loginUser,
|
|
onSaveAccomadation: (data)=>handleItineraryUpdate("Accomodation", data),
|
|
selectedItem: selectedItem, );
|
|
break;
|
|
case "Forex":
|
|
selectedWidget = ForexScreen( onClose: handleClose,apiData: widget.apiData, loginUser : widget.loginUser,
|
|
apiCountryData : widget.apiCountryData,
|
|
onSaveForex: (data)=>handleItineraryUpdate("Forex", data),
|
|
selectedItem: selectedItem);
|
|
break;
|
|
case "Flight":
|
|
default:
|
|
selectedWidget = FlightScreen(onClose: handleClose,loginUser : widget.loginUser,
|
|
onSaveFlight: (data)=>handleItineraryUpdate("Flight", data), apiData: widget.apiData,
|
|
selectedItem: selectedItem
|
|
);
|
|
break;
|
|
}
|
|
|
|
|
|
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
|
bool isMobile = sizingInfo.isMobile;
|
|
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
|
|
|
|
|
return Column(
|
|
// mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text("Itinerary",
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
),),
|
|
],
|
|
),
|
|
SizedBox(height: 8),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
border: Border.all(color: Color(0xFFF4F4FB)),
|
|
borderRadius: BorderRadius.circular(1),
|
|
color: Color(0xFFF4F4FB),
|
|
),
|
|
padding: EdgeInsets.all(5),
|
|
child: isMobile ?
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
children: _buildOptions(),
|
|
),
|
|
),
|
|
)
|
|
: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
// mainAxisSize: MainAxisSize.min,
|
|
children: _buildOptions(),
|
|
),
|
|
),
|
|
|
|
|
|
|
|
Column(
|
|
// mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
SizedBox(height: 2),
|
|
isSelected ? selectedWidget : selectedListWidget,
|
|
// TrainScreen()
|
|
],
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
});
|
|
}
|
|
|
|
List<Widget> _buildOptions() {
|
|
return [
|
|
_buildOption("Flight", itineraryData["Flight"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Taxi", itineraryData["Taxi"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Train", itineraryData["Train"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Bus", itineraryData["Bus"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Accomodation", itineraryData["Accomodation"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Forex", itineraryData["Forex"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Insurance", itineraryData["Insurance"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Visa", itineraryData["Visa"]?.isNotEmpty ?? false),
|
|
SizedBox(width: 20),
|
|
_buildOption("Miscellaneous", itineraryData["Miscellaneous"]?.isNotEmpty ?? false),
|
|
];
|
|
}
|
|
|
|
|
|
// List<Widget> _buildOptions() {
|
|
// return [
|
|
// _buildOption("Flight", itineraryData["Flight"]?.isNotEmpty ?? false),
|
|
// _buildOption("Flight"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Taxi"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Train"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Bus"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Accomodation"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Forex"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Insurance"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Visa"),
|
|
// SizedBox(width: 20),
|
|
// _buildOption("Miscellaneous"),
|
|
// ];
|
|
// }
|
|
|
|
Widget _buildOption(String title, bool hasData) {
|
|
return GestureDetector(
|
|
onTap: () {
|
|
setState(() {
|
|
selectedListOption = title;
|
|
isSelected = false;
|
|
});
|
|
},
|
|
child: Row(
|
|
children: [
|
|
|
|
if(hasData)
|
|
Icon(Icons.circle_notifications,color: Colors.green, size: 10,),
|
|
|
|
SizedBox(width: 5),
|
|
Text(title,
|
|
style: TextStyle(
|
|
fontSize: 13,
|
|
color: selectedListOption == title ? Colors.blueAccent : Color(0xFF575A74),
|
|
fontWeight:
|
|
selectedListOption == title ? FontWeight.bold : FontWeight.normal,)),
|
|
SizedBox(width: 5),
|
|
|
|
SizedBox(width: 5),
|
|
if (selectedListOption == title && widget.isViewMode == false)
|
|
GestureDetector(
|
|
onTap: () {
|
|
setState(() {
|
|
selectedOption = title;
|
|
isSelected = true;
|
|
selectedItem = null;
|
|
});
|
|
},
|
|
child: Icon(
|
|
Icons.add_circle,
|
|
color: Colors.blueAccent,
|
|
size: 18,
|
|
),
|
|
),
|
|
|
|
]
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
|