Exceptional Classes

This commit is contained in:
venbaittech 2025-06-21 19:17:07 +05:30
parent e33af3cd8a
commit 53fd28d65d
18 changed files with 819 additions and 311 deletions

View File

@ -817,7 +817,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
Navigator.pop( Navigator.pop(
context, context,
); // Close popup manually ); // Close popup manually
ApiService.viewPlan( ApiService.viewPlanTravelAgent(
context, context,
plan.planId, plan.planId,
isViewMode: isViewMode:

View File

@ -1,16 +1,20 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.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 '../../services/apiService.dart';
import '../../widgets/custom_confirmation_dialog.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 AccomodationScreen extends StatefulWidget { class AccomodationScreen extends StatefulWidget {
final List<Map<String, dynamic>> flightData; final List<Map<String, dynamic>> flightData;
final Function(bool) onClose; // Callback function final Map<String, dynamic>? apiDataForClass;
final Function(String, bool) onClose; // Callback function
final Function(Map<String, dynamic>) onSaveAccomadation; final Function(Map<String, dynamic>) onSaveAccomadation;
final void Function(bool)? onExceptionalClass;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
final String? tripType; final String? tripType;
@ -22,6 +26,8 @@ class AccomodationScreen extends StatefulWidget {
required this.loginUser, required this.loginUser,
required this.flightData, required this.flightData,
this.tripType, this.tripType,
this.apiDataForClass,
this.onExceptionalClass,
}); });
@override @override
@ -34,6 +40,10 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
// late Map<String, String> countryMap; // late Map<String, String> countryMap;
Map<String, String> countryMap = {}; Map<String, String> countryMap = {};
String? selectedClass;
String? exceptionalClass = "0";
bool hasExceptionalClass = false;
late ValueNotifier<String?> flightFirstTripDateNotifier; late ValueNotifier<String?> flightFirstTripDateNotifier;
late ValueNotifier<String?> flightLastTripDateNotifier; late ValueNotifier<String?> flightLastTripDateNotifier;
late ValueNotifier<String?> flightFirstToDestinationNotifier; late ValueNotifier<String?> flightFirstToDestinationNotifier;
@ -42,6 +52,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
final FocusNode _destinationFocusNode = FocusNode(); final FocusNode _destinationFocusNode = FocusNode();
final FocusNode _hotelNameFocusNode = FocusNode(); final FocusNode _hotelNameFocusNode = FocusNode();
final FocusNode _CategoryFocusNode = FocusNode();
final FocusNode _checkInFocusNode = FocusNode(); final FocusNode _checkInFocusNode = FocusNode();
final FocusNode _checkInTimeFocusNode = FocusNode(); final FocusNode _checkInTimeFocusNode = FocusNode();
final FocusNode _checkOutFocusNode = FocusNode(); final FocusNode _checkOutFocusNode = FocusNode();
@ -58,6 +69,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
bool _destinationFocused = false; bool _destinationFocused = false;
bool _isHotelNameFocused = false; bool _isHotelNameFocused = false;
bool _CategoryFocused = false;
bool _checkInFocus = false; bool _checkInFocus = false;
bool _checkInTimeFocus = false; bool _checkInTimeFocus = false;
bool _checkOutFocus = false; bool _checkOutFocus = false;
@ -78,11 +90,13 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
Map<String, dynamic> data = { Map<String, dynamic> data = {
"destination_city": _destinationController.text, "destination_city": _destinationController.text,
"hotel_name": _hotelNameController.text, "hotel_name": _hotelNameController.text,
"class": selectedClass,
"checkin_date": _checkInController.text, "checkin_date": _checkInController.text,
"checkin_time": _checkInTimeController.text, "checkin_time": _checkInTimeController.text,
"checkout_date": _checkOutController.text, "checkout_date": _checkOutController.text,
"checkout_time": _checkOutTimeController.text, "checkout_time": _checkOutTimeController.text,
"comments": _commentsController.text, "comments": _commentsController.text,
"is_this_exceptional": exceptionalClass,
"created_by": widget.loginUser, "created_by": widget.loginUser,
"updated_by": widget.loginUser, "updated_by": widget.loginUser,
}; };
@ -191,6 +205,16 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
_checkOutTimeController.text = '12:00'; // 12 PM _checkOutTimeController.text = '12:00'; // 12 PM
} }
}); });
if (widget.selectedItem != null &&
widget.selectedItem!["is_this_exceptional"] != null) {
exceptionalClass = widget.selectedItem!["is_this_exceptional"].toString();
}
// Set the selected value if available
if (widget.selectedItem != null && widget.selectedItem!["class"] != null) {
selectedClass = widget.selectedItem!["class"].toString();
}
} }
@override @override
@ -365,9 +389,13 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
return; // Stop execution if validation fails return; // Stop execution if validation fails
} else { } else {
widget.onSaveAccomadation(accomadationData); widget.onSaveAccomadation(accomadationData);
// if (hasExceptionalClass) {
// widget.onExceptionalClass?.call(true); // or false
// }
} }
widget.onClose(false); // Close screen after saving widget.onClose("Accomodation", false); // Close screen after saving
} }
@override @override
@ -421,6 +449,34 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
} }
List<Widget> _buildFirstRow(isDesktop) { List<Widget> _buildFirstRow(isDesktop) {
List<dynamic> purposeList = widget.apiDataForClass?['hotel_class'] ?? [];
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_key'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
// Default selected value
// selectedClass ??=
// dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [ return [
// Column( // Column(
// children: [ // children: [
@ -493,13 +549,13 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
), ),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldItnerarySubWrapper(
isFocused: _isHotelNameFocused, isFocused: _isHotelNameFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: // width:
isDesktop // isDesktop
? MediaQuery.of(context).size.width * 0.34 // ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, // : MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
@ -525,6 +581,147 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
], ],
], ],
), ),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Category *",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
// isFocused: focusStates["_class${index}Focused"] ?? false,
isFocused: false,
padding: const EdgeInsets.symmetric(horizontal: 0),
isDesktop: isDesktop,
child: SizedBox(
height: 40,
width: double.infinity,
child: DropdownSearch<Map<String, dynamic>>(
key:
selectedClass == null
? UniqueKey()
: ValueKey(selectedClass),
items: purposeList.cast<Map<String, dynamic>>(),
// selectedItem: purposeList.firstWhere(
// (item) => item['dropdown_key'] == selectedClass,
// orElse: () => {},
// ),
selectedItem:
selectedClass != null
? purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedClass,
orElse: () => {},
)
: null,
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
print("categotey - $item ");
final bool isNotAllowed = item['is_allowed'] == 'No';
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Text(
item['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: isNotAllowed ? Colors.redAccent : Colors.black,
),
),
);
},
),
dropdownDecoratorProps: const DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
// color: Colors.red,
color: Colors.black,
),
);
},
onChanged:
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) async {
if (newValue != null &&
newValue['is_allowed'] == 'No') {
final confirm = await showNotAllowedDialog(
context,
message:
"You are not entitled for this service. If you wish to continue with this service, you may require another approval.",
);
if (confirm) {
setState(() {
exceptionalClass = "1";
selectedClass = newValue['dropdown_key'];
});
print("Selected Purpose: ${selectedClass}");
} else {
setState(() {
exceptionalClass = "0";
selectedClass =
null; // Clear selection if user cancels
});
print(
"selectedItem resolved to: ${selectedClass}",
);
}
return;
} else if (newValue != null &&
newValue['is_allowed'] == 'yes') {
setState(() {
exceptionalClass = "0";
selectedClass = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedClass}");
});
}
}
: null,
),
),
),
if (errorMessages["class"] != null) ...[
SizedBox(height: 5), // Space before error message
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
],
],
),
// if (isDesktop) Spacer() else SizedBox(height: 8),
]; ];
} }
@ -1025,7 +1222,8 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // Close the dialog or screen widget.onClose("Accomodation", false);
// widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -8,7 +8,7 @@ import '../../widgets/custom_text_itnerary_sub.dart';
class BusScreen extends StatefulWidget { class BusScreen extends StatefulWidget {
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final Function(bool) onClose; final Function(String, bool) onClose;
final Function(Map<String, dynamic>) onSaveBus; final Function(Map<String, dynamic>) onSaveBus;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
@ -190,8 +190,8 @@ class _BusScreenState extends State<BusScreen> {
} else { } else {
widget.onSaveBus(busData); widget.onSaveBus(busData);
} }
widget.onClose("Bus", false);
widget.onClose(false); // Close screen after saving // widget.onClose(false); // Close screen after saving
} }
@override @override
@ -678,7 +678,8 @@ class _BusScreenState extends State<BusScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // Close the dialog or screen widget.onClose("Bus", false);
// widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -6,6 +6,7 @@ import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart'; import 'package:responsive_builder/responsive_builder.dart';
import '../../utils/auth_utils.dart'; import '../../utils/auth_utils.dart';
import '../../widgets/custom_confirmation_dialog.dart';
import '../../widgets/custom_radio_button.dart'; import '../../widgets/custom_radio_button.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';
@ -17,7 +18,7 @@ class FlightScreen extends StatefulWidget {
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final Map<String, dynamic>? apiDataForClass; final Map<String, dynamic>? apiDataForClass;
final String? loginUser; final String? loginUser;
final Function(bool) onClose; final Function(String, bool) onClose;
final Function(Map<String, dynamic>) onSaveFlight; final Function(Map<String, dynamic>) onSaveFlight;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final ValueNotifier<String?> tripTypeNotifier; final ValueNotifier<String?> tripTypeNotifier;
@ -60,6 +61,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?> exceptionalClass =
{}; // Store class selection for each trip
Map<int, String?> selectedFrom = {}; // 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 Map<int, String?> selectedTo = {}; // Store class selection for each trip
String? selectedvisa_available; String? selectedvisa_available;
@ -409,6 +412,7 @@ 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],
"is_this_exceptional": exceptionalClass[i],
// "from_place": countryMap[selectedFrom[i]], // "from_place": countryMap[selectedFrom[i]],
"from_place": selectedFrom[i], "from_place": selectedFrom[i],
"to_place": selectedTo[i], "to_place": selectedTo[i],
@ -505,6 +509,7 @@ 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();
exceptionalClass[index] = trip["is_this_exceptional"].toString();
selectedFrom[index] = trip["from_place"].toString(); selectedFrom[index] = trip["from_place"].toString();
selectedTo[index] = trip["to_place"].toString(); selectedTo[index] = trip["to_place"].toString();
// textControllers["_from${index}Controller"] = // textControllers["_from${index}Controller"] =
@ -545,7 +550,8 @@ class FlightScreenState extends State<FlightScreen> {
} }
widget.onSaveFlight(flightsData); // Send object to parent widget.onSaveFlight(flightsData); // Send object to parent
widget.onClose(false); // widget.onClose(false);
widget.onClose("Flight", false);
print("FlightData - $flightsData"); print("FlightData - $flightsData");
} }
@ -789,6 +795,16 @@ class FlightScreenState extends State<FlightScreen> {
selectedClasses = updatedClasses; // Update the map selectedClasses = updatedClasses; // Update the map
Map<int, String?> updatedExptionalClasses = {};
newIndex = 1;
for (int i = 1; i <= exceptionalClass.length; i++) {
if (i == index) continue; // Skip the one being deleted
updatedExptionalClasses[newIndex] = exceptionalClass[i];
newIndex++;
}
exceptionalClass = updatedExptionalClasses;
// Shift the selectedFrom map BEFORE removing the index // Shift the selectedFrom map BEFORE removing the index
Map<int, String?> updatedFrom = {}; Map<int, String?> updatedFrom = {};
newIndex = 1; newIndex = 1;
@ -1320,8 +1336,8 @@ class FlightScreenState extends State<FlightScreen> {
} }
// Default selected value // Default selected value
selectedClasses[index] ??= // selectedClasses[index] ??=
dropdownItems.isNotEmpty ? dropdownItems.first.value : null; // dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
// ------------------------------------------------- // -------------------------------------------------
DateTime? _selectedCheckOutDate; DateTime? _selectedCheckOutDate;
@ -2046,16 +2062,30 @@ class FlightScreenState extends State<FlightScreen> {
}, },
child: DropdownSearch<Map<String, dynamic>>( child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(), items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere( key:
(item) => item['dropdown_key'] == selectedClasses[index], selectedClasses[index] == null
orElse: () => {}, ? UniqueKey()
), : ValueKey(selectedClasses[index]),
// selectedItem: purposeList.firstWhere(
// (item) => item['dropdown_key'] == selectedClasses[index],
// orElse: () => {},
// ),
selectedItem:
selectedClasses[index] != null
? purposeList.firstWhere(
(item) =>
item['dropdown_key'] ==
selectedClasses[index],
orElse: () => {},
)
: null,
itemAsString: (item) => item['dropdown_value'] ?? '', itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: false, showSearchBox: false,
fit: FlexFit.loose, fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white), menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) { itemBuilder: (context, item, isSelected) {
final bool isNotAllowed = item['is_allowed'] == 'No';
return Padding( return Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
@ -2065,7 +2095,10 @@ class FlightScreenState extends State<FlightScreen> {
item['dropdown_value'] ?? '', item['dropdown_value'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black, color:
isNotAllowed
? Colors.redAccent
: Colors.black,
), ),
), ),
); );
@ -2124,14 +2157,67 @@ class FlightScreenState extends State<FlightScreen> {
}, },
onChanged: onChanged:
purposeList.isNotEmpty purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) { ? (Map<String, dynamic>? newValue) async {
setState(() { // if (newValue != null &&
selectedClasses[index] = // newValue['is_allowed'] == 'No') {
newValue?['dropdown_key']; // print('not allowed');
print( //
"Selected Class: ${selectedClasses[index]}", // exceptionalClass[index] = "1";
// } else if (newValue != null &&
// newValue['is_allowed'] == 'yes') {
// print('not allowed');
//
// exceptionalClass[index] = "0";
// }
//
// setState(() {
// selectedClasses[index] =
// newValue?['dropdown_key'];
// print(
// "Selected Class: ${selectedClasses[index]}",
// );
// });
if (newValue != null &&
newValue['is_allowed'] == 'No') {
final confirm = await showNotAllowedDialog(
context,
message:
"You are not entitled for this service. If you wish to continue with this service, you may require another approval.",
); );
});
if (confirm) {
setState(() {
exceptionalClass[index] = "1";
selectedClasses[index] =
newValue['dropdown_key'];
});
print(
"Selected Purpose: ${selectedClasses[index]}",
);
} else {
setState(() {
exceptionalClass[index] = "0";
selectedClasses[index] =
null; // Clear selection if user cancels
});
print(
"selectedItem resolved to: ${selectedClasses[index]}",
);
}
return;
} else if (newValue != null &&
newValue['is_allowed'] == 'yes') {
setState(() {
exceptionalClass[index] = "0";
selectedClasses[index] =
newValue?['dropdown_key'];
print(
"Selected Purpose: ${selectedClasses[index]}",
);
});
}
} }
: null, : null,
), ),
@ -2690,7 +2776,8 @@ class FlightScreenState extends State<FlightScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // Close the dialog or screen widget.onClose("Flight", false);
// widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -18,7 +18,7 @@ import 'package:http/http.dart' as http;
class ForexScreen extends StatefulWidget { class ForexScreen extends StatefulWidget {
final List<Map<String, dynamic>> flightData; final List<Map<String, dynamic>> flightData;
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final Function(bool) onClose; final Function(String, bool) onClose;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final List<dynamic>? apiCountryData; final List<dynamic>? apiCountryData;
final Function(Map<String, dynamic>) onSaveForex; final Function(Map<String, dynamic>) onSaveForex;
@ -366,8 +366,8 @@ class _ForexScreenState extends State<ForexScreen> {
} else { } else {
widget.onSaveForex(forexData); // Send object to parent widget.onSaveForex(forexData); // Send object to parent
} }
widget.onClose("Forex", false);
widget.onClose(false); // Close screen after saving // widget.onClose(false); // Close screen after saving
} }
DateTime? _parseDate(String date) { DateTime? _parseDate(String date) {
@ -2294,7 +2294,7 @@ class _ForexScreenState extends State<ForexScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // Close the dialog or screen widget.onClose("Forex", false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -11,7 +11,7 @@ import '../../widgets/custom_text_itnerary_sub.dart';
class InsuranceScreen extends StatefulWidget { class InsuranceScreen extends StatefulWidget {
final List<Map<String, dynamic>> flightData; final List<Map<String, dynamic>> flightData;
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final Function(bool) onClose; final Function(String, bool) onClose;
final Function(Map<String, dynamic>) onSaveInsurance; final Function(Map<String, dynamic>) onSaveInsurance;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
@ -290,8 +290,8 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
} else { } else {
widget.onSaveInsurance(InsuranceData); widget.onSaveInsurance(InsuranceData);
} }
widget.onClose("Insurance", false);
widget.onClose(false); // Close screen after saving // widget.onClose(false); // Close screen after saving
} }
DateTime? _parseDate(String date) { DateTime? _parseDate(String date) {
@ -1371,7 +1371,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // Close the dialog or screen widget.onClose("Insurance", false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -9,7 +9,8 @@ import '../../widgets/custom_text_itnerary_sub.dart';
class MiscellaneousScreen extends StatefulWidget { class MiscellaneousScreen extends StatefulWidget {
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final Function(bool) onClose; final Function(String, bool) onClose;
final Function(Map<String, dynamic>) onSaveMiscellaneous; final Function(Map<String, dynamic>) onSaveMiscellaneous;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final int? selectedIndex; final int? selectedIndex;
@ -137,7 +138,8 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
widget.onSaveMiscellaneous(miscellaneousData); // Send object to parent widget.onSaveMiscellaneous(miscellaneousData); // Send object to parent
} }
widget.onClose(false); // Close screen after saving widget.onClose("Miscellaneous", false); // Close screen after saving
// widget.onClose(false); // Close screen after saving
// Clear only if this is a new entry // Clear only if this is a new entry
// if (widget.selectedItem == null) { // if (widget.selectedItem == null) {
// _commentsController.clear(); // _commentsController.clear();
@ -281,9 +283,10 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
isFocused: _isHotelNameFocused, isFocused: _isHotelNameFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop width:
? MediaQuery.of(context).size.width * 0.34 isDesktop
: MediaQuery.of(context).size.width * 0.66, ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
width: double.infinity, width: double.infinity,
@ -291,7 +294,7 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
// focusNode: _taxiReqFocusNode, // focusNode: _taxiReqFocusNode,
items: purposeList.cast<Map<String, dynamic>>(), items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere( selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedSpecialType, (item) => item['dropdown_key'] == selectedSpecialType,
orElse: () => {}, orElse: () => {},
), ),
itemAsString: (item) => item['dropdown_value'] ?? '', itemAsString: (item) => item['dropdown_value'] ?? '',
@ -328,31 +331,23 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
if (selectedItem == null || selectedItem.isEmpty) { if (selectedItem == null || selectedItem.isEmpty) {
return Text( return Text(
"Select ", "Select ",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(color: Colors.grey, fontSize: 13),
color: Colors.grey,
fontSize: 13,
),
); );
} }
return Text( return Text(
selectedItem['dropdown_value'] ?? '', selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
fontSize: 12,
color: Colors.black,
),
); );
}, },
onChanged: onChanged:
purposeList.isNotEmpty purposeList.isNotEmpty
? (newValue) { ? (newValue) {
setState(() { setState(() {
selectedSpecialType = newValue as String?; selectedSpecialType = newValue as String?;
}); });
print( print("Updating form data: -> ${newValue ?? ""}");
"Updating form data: -> ${newValue ?? ""}", }
); : null,
}
: null,
), ),
), ),
), ),
@ -421,7 +416,8 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
_commentsController.clear(); _commentsController.clear();
widget.onClose(false); // Close the dialog or screen widget.onClose("Miscellaneous", false);
// widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -10,7 +10,7 @@ import '../../widgets/custom_text_itnerary_sub.dart';
class TaxiScreen extends StatefulWidget { class TaxiScreen extends StatefulWidget {
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final Function(bool) onClose; final Function(String, bool) onClose;
final Function(Map<String, dynamic>) onSavetaxi; final Function(Map<String, dynamic>) onSavetaxi;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
@ -199,8 +199,8 @@ class _TaxiScreenState extends State<TaxiScreen> {
} else { } else {
widget.onSavetaxi(taxiData); widget.onSavetaxi(taxiData);
} }
widget.onClose("Taxi", false);
widget.onClose(false); // Close screen after saving // widget.onClose(false); // Close screen after saving
} }
@override @override
@ -404,7 +404,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
// focusNode: _taxiReqFocusNode, // focusNode: _taxiReqFocusNode,
items: purposeList.cast<Map<String, dynamic>>(), items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere( selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedCarType, (item) => item['dropdown_key'] == selectedCarType,
orElse: () => {}, orElse: () => {},
), ),
itemAsString: (item) => item['dropdown_value'] ?? '', itemAsString: (item) => item['dropdown_value'] ?? '',
@ -456,16 +456,14 @@ class _TaxiScreenState extends State<TaxiScreen> {
); );
}, },
onChanged: onChanged:
purposeList.isNotEmpty purposeList.isNotEmpty
? (newValue) { ? (newValue) {
setState(() { setState(() {
selectedCarType = newValue as String?; selectedCarType = newValue as String?;
}); });
print( print("Updating form data: -> ${newValue ?? ""}");
"Updating form data: -> ${newValue ?? ""}", }
); : null,
}
: null,
), ),
), ),
), ),
@ -544,9 +542,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
isFocused: _taxiReqFocused, isFocused: _taxiReqFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: width:
isDesktop isDesktop
? MediaQuery.of(context).size.width * 0.34 ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66, : MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
width: double.infinity, width: double.infinity,
@ -554,7 +552,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
// focusNode: _taxiReqFocusNode, // focusNode: _taxiReqFocusNode,
items: purposeList.cast<Map<String, dynamic>>(), items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere( selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedReqTaxi, (item) => item['dropdown_key'] == selectedReqTaxi,
orElse: () => {}, orElse: () => {},
), ),
itemAsString: (item) => item['dropdown_value'] ?? '', itemAsString: (item) => item['dropdown_value'] ?? '',
@ -591,31 +589,23 @@ class _TaxiScreenState extends State<TaxiScreen> {
if (selectedItem == null || selectedItem.isEmpty) { if (selectedItem == null || selectedItem.isEmpty) {
return Text( return Text(
"Select ", "Select ",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(color: Colors.grey, fontSize: 13),
color: Colors.grey,
fontSize: 13,
),
); );
} }
return Text( return Text(
selectedItem['dropdown_value'] ?? '', selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
fontSize: 12,
color: Colors.black,
),
); );
}, },
onChanged: onChanged:
purposeList.isNotEmpty purposeList.isNotEmpty
? (newValue) { ? (newValue) {
setState(() { setState(() {
selectedReqTaxi = newValue as String?; selectedReqTaxi = newValue as String?;
}); });
print( print("Updating form data: -> ${newValue ?? ""}");
"Updating form data: -> ${newValue ?? ""}", }
); : null,
}
: null,
), ),
), ),
), ),
@ -974,7 +964,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // Close the dialog or screen widget.onClose("Taxi", false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -5,6 +5,7 @@ import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart'; import 'package:responsive_builder/responsive_builder.dart';
import '../../services/apiService.dart'; import '../../services/apiService.dart';
import '../../widgets/custom_confirmation_dialog.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';
@ -12,7 +13,7 @@ class TrainScreen extends StatefulWidget {
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final Map<String, dynamic>? apiDataForClass; final Map<String, dynamic>? apiDataForClass;
final Function(Map<String, dynamic>) onSavetrain; final Function(Map<String, dynamic>) onSavetrain;
final Function(bool) onClose; final Function(String, bool) onClose;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
final String? tripType; final String? tripType;
@ -67,6 +68,7 @@ class _TrainScreenState extends State<TrainScreen> {
bool _commentsFocus = false; bool _commentsFocus = false;
String? selectedClass; String? selectedClass;
String? exceptionalClass = "0";
String? selectedFrom; String? selectedFrom;
String? selectedTo; String? selectedTo;
@ -80,6 +82,7 @@ class _TrainScreenState extends State<TrainScreen> {
// "from_station": _fromController.text, // "from_station": _fromController.text,
"to_station": selectedTo, "to_station": selectedTo,
// "to_station": _toController.text, // "to_station": _toController.text,
"is_this_exceptional": exceptionalClass,
"date": _dateController.text, "date": _dateController.text,
"time": _timeController.text, "time": _timeController.text,
"comments": _trainCommentsController.text, "comments": _trainCommentsController.text,
@ -151,6 +154,11 @@ class _TrainScreenState extends State<TrainScreen> {
_dateController = initController("date"); _dateController = initController("date");
_timeController = initController("time"); _timeController = initController("time");
if (widget.selectedItem != null &&
widget.selectedItem!["is_this_exceptional"] != null) {
exceptionalClass = widget.selectedItem!["is_this_exceptional"].toString();
}
// Set the selected value if available // Set the selected value if available
if (widget.selectedItem != null && widget.selectedItem!["class"] != null) { if (widget.selectedItem != null && widget.selectedItem!["class"] != null) {
selectedClass = widget.selectedItem!["class"].toString(); selectedClass = widget.selectedItem!["class"].toString();
@ -288,8 +296,8 @@ class _TrainScreenState extends State<TrainScreen> {
} else { } else {
widget.onSavetrain(trainData); widget.onSavetrain(trainData);
} }
widget.onClose("Train", false);
widget.onClose(false); // Close screen after saving // widget.onClose(false); // Close screen after saving
} }
@override @override
@ -576,8 +584,8 @@ class _TrainScreenState extends State<TrainScreen> {
} }
// Default selected value // Default selected value
selectedClass ??= // selectedClass ??=
dropdownItems.isNotEmpty ? dropdownItems.first.value : null; // dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [ return [
Column( Column(
@ -631,17 +639,30 @@ class _TrainScreenState extends State<TrainScreen> {
height: 40, height: 40,
width: double.infinity, width: double.infinity,
child: DropdownSearch<Map<String, dynamic>>( child: DropdownSearch<Map<String, dynamic>>(
key:
selectedClass == null
? UniqueKey()
: ValueKey(selectedClass),
items: purposeList.cast<Map<String, dynamic>>(), items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedClass, // selectedItem: purposeList.firstWhere(
orElse: () => {}, // (item) => item['dropdown_key'] == selectedClass,
), // orElse: () => {},
// ),
selectedItem:
selectedClass != null
? purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedClass,
orElse: () => {},
)
: null,
itemAsString: (item) => item['dropdown_value'] ?? '', itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: false, showSearchBox: false,
fit: FlexFit.loose, fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white), menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) { itemBuilder: (context, item, isSelected) {
final bool isNotAllowed = item['is_allowed'] == 'No';
return Padding( return Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
@ -651,7 +672,7 @@ class _TrainScreenState extends State<TrainScreen> {
item['dropdown_value'] ?? '', item['dropdown_value'] ?? '',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black, color: isNotAllowed ? Colors.redAccent : Colors.black,
), ),
), ),
); );
@ -660,7 +681,10 @@ class _TrainScreenState extends State<TrainScreen> {
dropdownDecoratorProps: const DropDownDecoratorProps( dropdownDecoratorProps: const DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration( dropdownSearchDecoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 10,vertical: 10,), contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
), ),
), ),
dropdownBuilder: (context, selectedItem) { dropdownBuilder: (context, selectedItem) {
@ -682,14 +706,59 @@ class _TrainScreenState extends State<TrainScreen> {
); );
}, },
onChanged: onChanged:
purposeList.isNotEmpty purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) { ? (Map<String, dynamic>? newValue) async {
setState(() { if (newValue != null &&
selectedClass= newValue?['dropdown_key']; newValue['is_allowed'] == 'No') {
print("Selected Purpose: ${selectedClass}"); final confirm = await showNotAllowedDialog(
}); context,
} message:
: null, "You are not entitled for this service. If you wish to continue with this service, you may require another approval.",
);
if (confirm) {
setState(() {
exceptionalClass = "1";
selectedClass = newValue['dropdown_key'];
});
print("Selected Purpose: ${selectedClass}");
} else {
setState(() {
exceptionalClass = "0";
selectedClass =
null; // Clear selection if user cancels
});
print(
"selectedItem resolved to: ${selectedClass}",
);
}
return;
} else if (newValue != null &&
newValue['is_allowed'] == 'yes') {
setState(() {
exceptionalClass = "0";
selectedClass = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedClass}");
});
}
// if (newValue != null &&
// newValue['is_allowed'] == 'No') {
// print('not allowed');
//
// setState(() {
// exceptionalClass = "1";
// // hasExceptionalClass = true;
// });
// }
setState(() {
selectedClass = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedClass}");
});
}
: null,
), ),
), ),
), ),
@ -817,16 +886,16 @@ class _TrainScreenState extends State<TrainScreen> {
menuProps: const MenuProps(backgroundColor: Colors.white), menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: itemBuilder:
(context, item, isSelected) => Container( (context, item, isSelected) => Container(
color: Colors.white, color: Colors.white,
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
vertical: 6, vertical: 6,
), ),
child: Text( child: Text(
item, item,
style: GoogleFonts.poppins(fontSize: 11.5), style: GoogleFonts.poppins(fontSize: 11.5),
), ),
), ),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
@ -843,22 +912,20 @@ class _TrainScreenState extends State<TrainScreen> {
), ),
dropdownBuilder: dropdownBuilder:
(context, selectedItem) => Align( (context, selectedItem) => Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
selectedItem ?? "Select ", selectedItem ?? "Select ",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black, color: Colors.black,
),
),
), ),
),
),
onChanged: (String? newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
selectedFrom = selectedFrom =
countryMap.entries countryMap.entries
.firstWhere( .firstWhere((entry) => entry.value == newValue)
(entry) => entry.value == newValue,
)
.key; .key;
}); });
}, },
@ -952,16 +1019,16 @@ class _TrainScreenState extends State<TrainScreen> {
menuProps: const MenuProps(backgroundColor: Colors.white), menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: itemBuilder:
(context, item, isSelected) => Container( (context, item, isSelected) => Container(
color: Colors.white, color: Colors.white,
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
vertical: 6, vertical: 6,
), ),
child: Text( child: Text(
item, item,
style: GoogleFonts.poppins(fontSize: 11.5), style: GoogleFonts.poppins(fontSize: 11.5),
), ),
), ),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
@ -978,22 +1045,20 @@ class _TrainScreenState extends State<TrainScreen> {
), ),
dropdownBuilder: dropdownBuilder:
(context, selectedItem) => Align( (context, selectedItem) => Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
selectedItem ?? "Select ", selectedItem ?? "Select ",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black, color: Colors.black,
),
),
), ),
),
),
onChanged: (String? newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
selectedTo = selectedTo =
countryMap.entries countryMap.entries
.firstWhere( .firstWhere((entry) => entry.value == newValue)
(entry) => entry.value == newValue,
)
.key; .key;
}); });
}, },
@ -1174,7 +1239,8 @@ class _TrainScreenState extends State<TrainScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // widget.onClose(false);
widget.onClose("Train", false);
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -13,7 +13,7 @@ class VisaScreen extends StatefulWidget {
final Map<String, dynamic>? apiData; final Map<String, dynamic>? apiData;
final List<dynamic>? apiCountryData; final List<dynamic>? apiCountryData;
final Function(bool) onClose; final Function(String, bool) onClose;
final Function(Map<String, dynamic>) onSaveVisa; final Function(Map<String, dynamic>) onSaveVisa;
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
@ -259,8 +259,8 @@ class _VisaScreenState extends State<VisaScreen> {
} else { } else {
widget.onSaveVisa(visaData); widget.onSaveVisa(visaData);
} }
widget.onClose("Visa", false);
widget.onClose(false); // Close screen after saving // widget.onClose(false); // Close screen after saving
} }
@override @override
@ -513,9 +513,10 @@ class _VisaScreenState extends State<VisaScreen> {
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
isFocused: _isHotelNameFocused, isFocused: _isHotelNameFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop width:
? MediaQuery.of(context).size.width * 0.34 isDesktop
: MediaQuery.of(context).size.width * 0.66, ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: DropdownSearch<String>( child: DropdownSearch<String>(
@ -527,16 +528,16 @@ class _VisaScreenState extends State<VisaScreen> {
menuProps: const MenuProps(backgroundColor: Colors.white), menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: itemBuilder:
(context, item, isSelected) => Container( (context, item, isSelected) => Container(
color: Colors.white, color: Colors.white,
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
vertical: 6, vertical: 6,
), ),
child: Text( child: Text(
item, item,
style: GoogleFonts.poppins(fontSize: 11.5), style: GoogleFonts.poppins(fontSize: 11.5),
), ),
), ),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
@ -553,18 +554,21 @@ class _VisaScreenState extends State<VisaScreen> {
), ),
dropdownBuilder: dropdownBuilder:
(context, selectedItem) => Align( (context, selectedItem) => Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
selectedItem ?? "Select ", selectedItem ?? "Select ",
style: GoogleFonts.poppins(fontSize: 12,color: Colors.black,), style: GoogleFonts.poppins(
), fontSize: 12,
), color: Colors.black,
),
),
),
onChanged: (String? newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
selectedCountry = selectedCountry =
countryMap.entries.firstWhere( countryMap.entries
(entry) => entry.value == newValue, .firstWhere((entry) => entry.value == newValue)
).key; .key;
}); });
}, },
), ),
@ -635,7 +639,7 @@ class _VisaScreenState extends State<VisaScreen> {
child: DropdownSearch<Map<String, dynamic>>( child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(), items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere( selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedPurpose, (item) => item['dropdown_key'] == selectedPurpose,
orElse: () => {}, orElse: () => {},
), ),
itemAsString: (item) => item['dropdown_value'] ?? '', itemAsString: (item) => item['dropdown_value'] ?? '',
@ -662,7 +666,10 @@ class _VisaScreenState extends State<VisaScreen> {
dropdownDecoratorProps: const DropDownDecoratorProps( dropdownDecoratorProps: const DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration( dropdownSearchDecoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 10,vertical: 10,), contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
), ),
), ),
dropdownBuilder: (context, selectedItem) { dropdownBuilder: (context, selectedItem) {
@ -692,14 +699,14 @@ class _VisaScreenState extends State<VisaScreen> {
// EdgeInsets.symmetric(horizontal: 10), // Proper padding // EdgeInsets.symmetric(horizontal: 10), // Proper padding
// ), // ),
onChanged: onChanged:
purposeList.isNotEmpty purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) { ? (Map<String, dynamic>? newValue) {
setState(() { setState(() {
selectedPurpose= newValue?['dropdown_key']; selectedPurpose = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedPurpose}"); print("Selected Purpose: ${selectedPurpose}");
}); });
} }
: null, : null,
), ),
), ),
), ),
@ -826,7 +833,8 @@ class _VisaScreenState extends State<VisaScreen> {
// Close Button // Close Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
widget.onClose(false); // Close the dialog or screen widget.onClose("Visa", false);
// widget.onClose(false); // Close the dialog or screen
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color

View File

@ -133,7 +133,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
widget.isViewMode widget.isViewMode
? null ? null
: () { : () {
checkClass(); widget.onAddNew("Flight", true);
// checkClass();
print("New data"); print("New data");
}, },
child: Row( child: Row(

View File

@ -298,6 +298,8 @@ class _CreatePlansState extends State<CreatePlan> {
context.go('/listPlan'); context.go('/listPlan');
} else if (currentUri == "/approver/plans") { } else if (currentUri == "/approver/plans") {
context.go('/approvallist'); context.go('/approvallist');
} else if (currentUri == "/travelagent/trips") {
context.go('/listTravelAgentPlan');
} else { } else {
isApprover ? context.go('/approvallist') : context.go('/listPlan'); isApprover ? context.go('/approvallist') : context.go('/listPlan');
} }
@ -381,6 +383,8 @@ class CreateNewPlansState extends State<CreateNewPlan> {
final TextEditingController _tripTitleController = TextEditingController(); final TextEditingController _tripTitleController = TextEditingController();
final TextEditingController _descriptionController = TextEditingController(); final TextEditingController _descriptionController = TextEditingController();
final TextEditingController _excepntldescriptionController =
TextEditingController();
final TextEditingController _remarksController = TextEditingController(); final TextEditingController _remarksController = TextEditingController();
// final FocusNode _tripTitleFocusNode = FocusNode(); // final FocusNode _tripTitleFocusNode = FocusNode();
@ -416,6 +420,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
bool showDomestic = false; bool showDomestic = false;
bool showInternational = false; bool showInternational = false;
bool hasAction = true; bool hasAction = true;
bool hasExceptionalClass = false;
late Map<String, String> costCenterMap; late Map<String, String> costCenterMap;
List<String> costCenterIds = []; List<String> costCenterIds = [];
@ -445,10 +450,10 @@ class CreateNewPlansState extends State<CreateNewPlan> {
List<Map<String, dynamic>> insuranceList = []; List<Map<String, dynamic>> insuranceList = [];
List<Map<String, dynamic>> accommodationList = []; List<Map<String, dynamic>> accommodationList = [];
List<Map<String, dynamic>> trainList = []; List<Map<String, dynamic>> trainList = [];
List<Map<String, dynamic>> flightList = [];
List<Map<String, dynamic>> busList = []; List<Map<String, dynamic>> busList = [];
List<Map<String, dynamic>> taxiList = []; List<Map<String, dynamic>> taxiList = [];
List<Map<String, dynamic>> forexList = []; List<Map<String, dynamic>> forexList = [];
List<Map<String, dynamic>> flightList = [];
List<Map<String, dynamic>> planStatusList = []; List<Map<String, dynamic>> planStatusList = [];
@ -471,6 +476,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
"is_billable": _selectedIsBillable, "is_billable": _selectedIsBillable,
"purpose_of_travel": selectedPurpose, "purpose_of_travel": selectedPurpose,
"description": _descriptionController.text, "description": _descriptionController.text,
"exceptional_plan_reason": _excepntldescriptionController.text,
"functional_department": selectedFuncDept, "functional_department": selectedFuncDept,
"so_number": "12345", "so_number": "12345",
"created_by": selfId, "created_by": selfId,
@ -495,6 +501,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
"is_billable", "is_billable",
"purpose_of_travel", "purpose_of_travel",
"description", "description",
"excepntldescription",
"functional_department", "functional_department",
]; ];
@ -535,6 +542,13 @@ class CreateNewPlansState extends State<CreateNewPlan> {
print("Updated $type List: $newList"); print("Updated $type List: $newList");
} }
void handleExcentionalClass(bool val) {
print("handleExcentionalClass - $val");
setState(() {
hasExceptionalClass = val;
});
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -652,6 +666,13 @@ class CreateNewPlansState extends State<CreateNewPlan> {
_descriptionController.text = _descriptionController.text =
widget.selectedPlanData['description'] ?? ''; widget.selectedPlanData['description'] ?? '';
_excepntldescriptionController.text =
widget.selectedPlanData['exceptional_plan_reason'] ?? '';
if (_excepntldescriptionController.text != "") {
hasExceptionalClass = true;
}
_selectedTripType = widget.selectedPlanData['trip_type']; _selectedTripType = widget.selectedPlanData['trip_type'];
flightTripTypeNotifier.value = widget.selectedPlanData['trip_type']; flightTripTypeNotifier.value = widget.selectedPlanData['trip_type'];
_selectedIsBillable = _selectedIsBillable =
@ -1136,6 +1157,8 @@ class CreateNewPlansState extends State<CreateNewPlan> {
"cost_center_id": selectedCostCenterId, "cost_center_id": selectedCostCenterId,
"functional_department": selectedFuncDept, "functional_department": selectedFuncDept,
"purpose_of_travel": selectedPurpose, "purpose_of_travel": selectedPurpose,
if (hasExceptionalClass)
"exceptional_plan_reason": _excepntldescriptionController.text,
}; };
print("validateForm.....3"); print("validateForm.....3");
for (var entry in requiredFields.entries) { for (var entry in requiredFields.entries) {
@ -1268,8 +1291,55 @@ class CreateNewPlansState extends State<CreateNewPlan> {
} }
} }
Future<void> checkExceptionalClass() async {
// pretend we fetch something
await Future.delayed(Duration(seconds: 1)); // Example async operation
int exceptionalCount = 0;
bool hasExceptional(List<Map<String, dynamic>> list) {
return list.any(
(item) =>
item['is_this_exceptional']?.toString() == '1' &&
item['is_active']?.toString() == '1',
);
}
bool hasExceptionalInFlights(List<Map<String, dynamic>> flights) {
for (var flight in flights) {
if (flight['is_active']?.toString() == '1') {
final trips = flight['trips'];
if (trips is List) {
final exceptionalTrip = trips.any(
(trip) => trip['is_this_exceptional']?.toString() == '1',
);
if (exceptionalTrip) return true;
}
}
}
return false;
}
if (hasExceptionalInFlights(flightList)) exceptionalCount++;
if (hasExceptional(trainList)) exceptionalCount++;
if (hasExceptional(accommodationList)) exceptionalCount++;
setState(() {
hasExceptionalClass = exceptionalCount >= 1;
if (!hasExceptionalClass) {
_excepntldescriptionController.text = '';
}
});
print("hasExceptionalClass: $hasExceptionalClass");
}
void handleSubmit() { void handleSubmit() {
setState(() async { setState(() async {
await checkExceptionalClass();
print("Handle Submit....after check");
print("Hansle Submit....11"); print("Hansle Submit....11");
if (validateForm() && temporaryMessage == null) { if (validateForm() && temporaryMessage == null) {
print("Hansle Submit....11222"); print("Hansle Submit....11222");
@ -1690,17 +1760,18 @@ class CreateNewPlansState extends State<CreateNewPlan> {
? Row( ? Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// _buildNonDescriptionColumn(), //
// SizedBox(width: 25),
_buildDescriptionColumn(isDesktop), _buildDescriptionColumn(isDesktop),
SizedBox(width: 25),
if (hasExceptionalClass) _buildNonDescriptionColumn(),
], ],
) )
: Column( : Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// _buildNonDescriptionColumn(),
// SizedBox(height: 15),
_buildDescriptionColumn(isDesktop), _buildDescriptionColumn(isDesktop),
SizedBox(height: 15),
_buildNonDescriptionColumn(),
], ],
), ),
@ -1743,6 +1814,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
apiDataForClass: apiDataForClass, apiDataForClass: apiDataForClass,
apiCountryData: apiCountryData, apiCountryData: apiCountryData,
onItineraryUpdate: handleItineraryUpdate, onItineraryUpdate: handleItineraryUpdate,
onExeptionalClass: handleExcentionalClass,
loginUser: selfId, loginUser: selfId,
selectedPlanData: planData, selectedPlanData: planData,
isViewMode: widget.isViewMode, isViewMode: widget.isViewMode,
@ -3248,7 +3320,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Trip Name", // Your label "Reason For Exceptional Class *", // Your label
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -3256,32 +3328,54 @@ class CreateNewPlansState extends State<CreateNewPlan> {
), ),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldWrapper(
isFocused: false, isFocused: focusStates["excepntldescriptionFocused"] ?? false,
// isFocused: _isTripTitleFocused, // isFocused: _isdescriptionFocused,
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.42
: null,
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 35, height: 55,
child: TextField( child: TextField(
// focusNode: _tripTitleFocusNode, focusNode: focusNodes["excepntldescriptionFocusNode"],
controller: _tripTitleController, controller: _excepntldescriptionController,
maxLines: 2,
keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Trip Name", labelText: "Exceptional Description",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey), labelStyle: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey,
),
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 1),
), ),
), ),
), ),
), ),
if (validationErrors["exceptional_plan_reason"] != null)
Padding(
padding: EdgeInsets.only(top: 4),
child: Text(
validationErrors["exceptional_plan_reason"]!,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.red,
),
),
),
], ],
), ),
], ],
), ),
SizedBox(height: 8),
], ],
); );
} }

View File

@ -34,6 +34,8 @@ class DynamicItinerary extends StatefulWidget {
final String? loginUser; final String? loginUser;
final Function(String, List<Map<String, dynamic>>) final Function(String, List<Map<String, dynamic>>)
onItineraryUpdate; // Updated Signature onItineraryUpdate; // Updated Signature
final void Function(bool)? onExeptionalClass;
final Map<String, dynamic> selectedPlanData; final Map<String, dynamic> selectedPlanData;
final bool isViewMode; final bool isViewMode;
final GlobalKey<FlightScreenState> flightScreenKey; final GlobalKey<FlightScreenState> flightScreenKey;
@ -48,6 +50,7 @@ class DynamicItinerary extends StatefulWidget {
required this.selectedPlanData, required this.selectedPlanData,
required this.isViewMode, required this.isViewMode,
required this.hasAction, required this.hasAction,
this.onExeptionalClass,
this.tripType, this.tripType,
this.apiDataForClass, this.apiDataForClass,
required this.tripTypeNotifier, required this.tripTypeNotifier,
@ -64,6 +67,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
String? _tripType; String? _tripType;
String selectedOption = ""; String selectedOption = "";
String selectedListOption = ""; String selectedListOption = "";
String selectedActiveTab = "";
bool isSelected = false; bool isSelected = false;
Map<String, dynamic>? selectedItem; Map<String, dynamic>? selectedItem;
@ -400,7 +404,8 @@ class DynamicItineraryState extends State<DynamicItinerary> {
return false; // No itinerary data available return false; // No itinerary data available
} }
void handleClose(bool value) { void handleMClose(bool value) {
print("handleClos- $isSelected");
setState(() { setState(() {
selectedOption = ""; selectedOption = "";
isSelected = value; isSelected = value;
@ -409,6 +414,17 @@ class DynamicItineraryState extends State<DynamicItinerary> {
}); });
} }
void handleClose(name, bool value) {
print("handleMClos- $name, $isSelected");
setState(() {
selectedListOption = name;
selectedOption = "";
isSelected = value;
selectedIndex = null;
selectedItem = null;
});
}
void handleEdit(bool value, selectedItem, title) { void handleEdit(bool value, selectedItem, title) {
setState(() { setState(() {
selectedOption = title; selectedOption = title;
@ -420,6 +436,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
} }
void handlecreateNewPlan(name, bool value) { void handlecreateNewPlan(name, bool value) {
print("handlecreateNewPlan- $name , $value");
setState(() { setState(() {
selectedOption = name; selectedOption = name;
isSelected = value; isSelected = value;
@ -710,6 +727,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
break; break;
case "Miscellaneous": case "Miscellaneous":
selectedWidget = MiscellaneousScreen( selectedWidget = MiscellaneousScreen(
// onClose: handleClose,
onClose: handleClose, onClose: handleClose,
apiData: widget.apiData, apiData: widget.apiData,
loginUser: widget.loginUser, loginUser: widget.loginUser,
@ -723,10 +741,12 @@ class DynamicItineraryState extends State<DynamicItinerary> {
selectedWidget = AccomodationScreen( selectedWidget = AccomodationScreen(
onClose: handleClose, onClose: handleClose,
loginUser: widget.loginUser, loginUser: widget.loginUser,
apiDataForClass: widget.apiDataForClass,
onSaveAccomadation: onSaveAccomadation:
(data) => handleItineraryUpdate("Accomodation", data), (data) => handleItineraryUpdate("Accomodation", data),
selectedItem: selectedItem, selectedItem: selectedItem,
flightData: itineraryData["Flight"]!, flightData: itineraryData["Flight"]!,
onExceptionalClass: widget.onExeptionalClass,
); );
break; break;
case "Forex": case "Forex":
@ -747,6 +767,7 @@ class DynamicItineraryState extends State<DynamicItinerary> {
tripTypeNotifier: widget.tripTypeNotifier, tripTypeNotifier: widget.tripTypeNotifier,
hasAction: widget.hasAction, hasAction: widget.hasAction,
tripType: widget.tripType, tripType: widget.tripType,
// onClose: handleMClose,
onClose: handleClose, onClose: handleClose,
loginUser: widget.loginUser, loginUser: widget.loginUser,
onSaveFlight: (data) => handleItineraryUpdate("Flight", data), onSaveFlight: (data) => handleItineraryUpdate("Flight", data),
@ -758,71 +779,6 @@ class DynamicItineraryState extends State<DynamicItinerary> {
break; break;
} }
// return ResponsiveBuilder(builder: (context, sizingInfo) {
// bool isMobile = sizingInfo.isMobile;
// bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
//
// return Column(
// // mainAxisSize: MainAxisSize.min,
// children: [
// Transform.translate(
// offset: Offset(0, 20),
// child: Container(
// decoration: BoxDecoration(
// border: Border(
// bottom: BorderSide(color: Color(0xFFF4F4FB), width: 2)),
// borderRadius: BorderRadius.circular(1),
// color: Color(0xFFF4F4FB),
// ),
// margin: EdgeInsets.symmetric(
// horizontal: MediaQuery.of(context).size.width *
// 0.05, // 30% of screen width as horizontal padding
// vertical: MediaQuery.of(context).size.height *
// 0, // 5% of screen height as vertical padding
// ),
// child: isMobile
// ? Expanded(
// child: SingleChildScrollView(
// scrollDirection: Axis.horizontal,
// child: Row(
// children: _buildOptions(),
// ),
// ),
// )
// : Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// // mainAxisSize: MainAxisSize.min,
// children: _buildOptions(),
// ),
// ),
// ),
//
//
// Container(
// decoration: BoxDecoration(
// // border:
// // Border(bottom: BorderSide(color: Colors.black, width: 2)),
//
// border: Border.all(color: Colors.green, width: 1.5),
// borderRadius: BorderRadius.circular(1),
// color: Colors.yellowAccent.shade100,
// ),
// margin: EdgeInsets.only(top: 0),
// child: Column(
// // mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// SizedBox(height: 2),
// isSelected ? selectedWidget : selectedListWidget,
// // TrainScreen()
// ],
// ),
// ),
//
// ],
// );
// });
return ResponsiveBuilder( return ResponsiveBuilder(
builder: (context, sizingInfo) { builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile; bool isMobile = sizingInfo.isMobile;
@ -964,19 +920,69 @@ class DynamicItineraryState extends State<DynamicItinerary> {
}).toList(); }).toList();
} }
bool checkClass() {
if (widget.hasAction) {
if (widget.tripType?.isNotEmpty == true) {
print("Teppp - ${widget.tripType}");
return true;
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Select Trip Type'),
content: const Text(
'Please select a trip type before selecting services.',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('OK'),
),
],
);
},
);
return false;
}
} else {
print("Teppp No - ${widget.tripType}");
return true; // still allow it when `hasAction` is false
}
}
Widget _buildOption(Map<String, dynamic> service, bool hasData) { Widget _buildOption(Map<String, dynamic> service, bool hasData) {
String name = service['name']; String name = service['name'];
String iconUrl = service['icon']; // Can be empty string String iconUrl = service['icon']; // Can be empty string
IconData fallbackIcon = _getLocalIconForService(name); IconData fallbackIcon = _getLocalIconForService(name);
bool isOptionSelected = selectedListOption == name; // bool isOptionSelected = selectedListOption == name;
bool isOptionSelected = selectedActiveTab == name;
// bool isOptionSelected =
// hasData ? selectedListOption == name : selectedOption == name;
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
setState(() { if (checkClass()) {
selectedListOption = name; setState(() {
isSelected = false; if (hasData) {
}); selectedListOption = name;
selectedActiveTab = name;
isSelected = false;
} else {
selectedOption = name;
selectedActiveTab = name;
isSelected = true;
selectedItem = null;
}
});
}
// setState(() {
// selectedListOption = name;
// isSelected = false;
// // selectedOption = name;
// // isSelected = true;
// });
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -1,3 +1,3 @@
//api url //api url
// const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be'; const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be';
const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; // const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be';

View File

@ -680,11 +680,7 @@ final List<Map<String, dynamic>> menuItems = [
// 'label': 'Template List' // 'label': 'Template List'
// }, // },
// {'value': '/template', 'icon': Icons.ac_unit_sharp, 'label': 'Template'}, // {'value': '/template', 'icon': Icons.ac_unit_sharp, 'label': 'Template'},
{ {'value': '/report', 'icon': Icons.auto_graph, 'label': 'Reports'},
'value': '/report',
'icon': Icons.auto_graph,
'label': 'Reports',
},
{ {
'value': '/CreateUserDetails', 'value': '/CreateUserDetails',
'icon': Icons.account_circle, 'icon': Icons.account_circle,

View File

@ -81,6 +81,10 @@ final GoRouter router = GoRouter(
path: '/approver/plans', path: '/approver/plans',
builder: (context, state) => CreatePlan(), builder: (context, state) => CreatePlan(),
), ),
GoRoute(
path: '/travelagent/trips',
builder: (context, state) => CreatePlan(),
),
GoRoute( GoRoute(
path: '/listUser', path: '/listUser',
builder: (context, state) => UserListScreen(), builder: (context, state) => UserListScreen(),

View File

@ -643,6 +643,25 @@ class ApiService {
} }
} }
static Future<void> viewPlanTravelAgent(
BuildContext context,
String planId, {
bool isViewMode = false,
bool isMyTrips = false,
}) async {
try {
Map<String, dynamic> planData = await getViewPlanEdit(planId);
print("ViewAAA - $planData");
context.go(
'/travelagent/trips',
extra: {'planData': planData, 'isViewMode': isViewMode},
);
} catch (e) {
print("Error fetching plan: $e");
}
}
Future<Map<String, dynamic>> fetchUserApprovalList() async { Future<Map<String, dynamic>> fetchUserApprovalList() async {
String? orgId = await getOrgId(); String? orgId = await getOrgId();
String? userId = await getUserId(); String? userId = await getUserId();
@ -899,8 +918,8 @@ class ApiService {
// download the Template for bulk upload the user // download the Template for bulk upload the user
Future<void> getDownloadUserTemplateForUpload() async { Future<void> getDownloadUserTemplateForUpload() async {
final String apiUrldata =
final String apiUrldata = '$apiUrl/api/user/userUploadTemplate'; // download the Template for bulk upload user => api '$apiUrl/api/user/userUploadTemplate'; // download the Template for bulk upload user => api
// final String apiUrldata = '$apiUrl/auth/googlelogin'; // final String apiUrldata = '$apiUrl/auth/googlelogin';
@ -930,9 +949,9 @@ class ApiService {
// Create a link element to trigger the download // Create a link element to trigger the download
final anchor = final anchor =
html.AnchorElement(href: url) html.AnchorElement(href: url)
..setAttribute('download', 'user_file.xlsx') ..setAttribute('download', 'user_file.xlsx')
..click(); ..click();
// Revoke the download URL to free up resources // Revoke the download URL to free up resources
html.Url.revokeObjectUrl(url); html.Url.revokeObjectUrl(url);
@ -962,7 +981,6 @@ class ApiService {
} }
} }
//---------------------------------------User Management----------------------------------- //---------------------------------------User Management-----------------------------------
Future<Map<String, dynamic>> getSingleUser(int userId) async { Future<Map<String, dynamic>> getSingleUser(int userId) async {
@ -1511,7 +1529,7 @@ class ApiService {
// ----------------------- User Management - CheckDuplicate end here ---------------------------------- // ----------------------- User Management - CheckDuplicate end here ----------------------------------
// ----------------------- Report ------------------------- // ----------------------- Report -------------------------
Future<Map<String, dynamic>> CallReports(String apiRoute,String body) async { Future<Map<String, dynamic>> CallReports(String apiRoute, String body) async {
String apiUrldata = '$apiUrl/api/$apiRoute'; String apiUrldata = '$apiUrl/api/$apiRoute';
final token = await getToken(); final token = await getToken();
@ -1521,8 +1539,11 @@ class ApiService {
final response = await http.post( final response = await http.post(
Uri.parse(apiUrldata), Uri.parse(apiUrldata),
headers: {'Authorization': 'Bearer $token','Content-Type': 'application/json'}, headers: {
body: body 'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: body,
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
@ -1539,14 +1560,20 @@ class ApiService {
} }
} }
Future<void> reportExcelDownload(String apiRoute,String body,String name) async { Future<void> reportExcelDownload(
String apiRoute,
String body,
String name,
) async {
final String apiUrldata = '$apiUrl/api/$apiRoute'; final String apiUrldata = '$apiUrl/api/$apiRoute';
// Sanitize name for filename (optional) // Sanitize name for filename (optional)
final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); // remove any special chars if needed final safeName = name.replaceAll(
RegExp(r'[^\w\s-]'),
'',
); // remove any special chars if needed
final excelName = '$safeName.xlsx'; final excelName = '$safeName.xlsx';
final token = await getToken(); final token = await getToken();
if (token == null) { if (token == null) {
@ -1554,9 +1581,12 @@ class ApiService {
} }
final response = await http.post( final response = await http.post(
Uri.parse(apiUrldata), Uri.parse(apiUrldata),
headers: {'Authorization': 'Bearer $token','Content-Type': 'application/json'}, headers: {
body: body 'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: body,
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
@ -1571,9 +1601,9 @@ class ApiService {
// Create a link element to trigger the download // Create a link element to trigger the download
final anchor = final anchor =
html.AnchorElement(href: url) html.AnchorElement(href: url)
..setAttribute('download', excelName) ..setAttribute('download', excelName)
..click(); ..click();
// Revoke the download URL to free up resources // Revoke the download URL to free up resources
html.Url.revokeObjectUrl(url); html.Url.revokeObjectUrl(url);
@ -1587,5 +1617,6 @@ class ApiService {
throw Exception('Failed to Download'); throw Exception('Failed to Download');
} }
} }
// ----------------------- Report -------------------------
// ----------------------- Report -------------------------
} }

View File

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
Future<bool> showNotAllowedDialog(
BuildContext context, {
String? message,
}) async {
return await showDialog<bool>(
context: context,
barrierDismissible: false, // Force user to choose
builder: (context) {
return AlertDialog(
title: const Text('Notice'),
content: Text(
message ?? 'This class is not allowed. Do you want to continue?',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false), // Cancel
child: const Text('Cancel'),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(true), // OK
child: const Text('OK'),
),
],
);
},
) ??
false; // Default to false if dialog is dismissed
}