Current Time Validations
This commit is contained in:
parent
5ccb201b7a
commit
de960412a0
@ -15,13 +15,14 @@ class AccomodationScreen extends StatefulWidget {
|
||||
final String? loginUser;
|
||||
final String? tripType;
|
||||
|
||||
AccomodationScreen(
|
||||
{required this.onClose,
|
||||
required this.onSaveAccomadation,
|
||||
required this.selectedItem,
|
||||
required this.loginUser,
|
||||
required this.flightData,
|
||||
this.tripType});
|
||||
AccomodationScreen({
|
||||
required this.onClose,
|
||||
required this.onSaveAccomadation,
|
||||
required this.selectedItem,
|
||||
required this.loginUser,
|
||||
required this.flightData,
|
||||
this.tripType,
|
||||
});
|
||||
|
||||
@override
|
||||
_AccomodationScreenState createState() => _AccomodationScreenState();
|
||||
@ -107,15 +108,23 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
super.initState();
|
||||
|
||||
_addFocusListener(
|
||||
_destinationFocusNode, (focus) => _destinationFocused = focus);
|
||||
_destinationFocusNode,
|
||||
(focus) => _destinationFocused = focus,
|
||||
);
|
||||
_addFocusListener(
|
||||
_hotelNameFocusNode, (focus) => _isHotelNameFocused = focus);
|
||||
_hotelNameFocusNode,
|
||||
(focus) => _isHotelNameFocused = focus,
|
||||
);
|
||||
_addFocusListener(_checkInFocusNode, (focus) => _checkInFocus = focus);
|
||||
_addFocusListener(
|
||||
_checkInTimeFocusNode, (focus) => _checkInTimeFocus = focus);
|
||||
_checkInTimeFocusNode,
|
||||
(focus) => _checkInTimeFocus = focus,
|
||||
);
|
||||
_addFocusListener(_checkOutFocusNode, (focus) => _checkOutFocus = focus);
|
||||
_addFocusListener(
|
||||
_checkOutTimeFocusNode, (focus) => _checkOutTimeFocus = focus);
|
||||
_checkOutTimeFocusNode,
|
||||
(focus) => _checkOutTimeFocus = focus,
|
||||
);
|
||||
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
|
||||
|
||||
_destinationController = initController("destination_city");
|
||||
@ -149,25 +158,29 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
flightFirstToDestinationNotifier.value = result['firstToDestination'];
|
||||
|
||||
print(
|
||||
"flightfirstToDestinationNotifier: $flightFirstToDestinationNotifier.value ");
|
||||
"flightfirstToDestinationNotifier: $flightFirstToDestinationNotifier.value ",
|
||||
);
|
||||
|
||||
// ✅ Only set controller after value is updated
|
||||
// final parsedDate = DateTime.tryParse(flightFirstTripDateNotifier.value ?? '');
|
||||
final parsedDate = DateFormat("dd-MM-yyyy")
|
||||
.parse(flightFirstTripDateNotifier.value ?? '');
|
||||
final parsedDate = DateFormat(
|
||||
"dd-MM-yyyy",
|
||||
).parse(flightFirstTripDateNotifier.value ?? '');
|
||||
if (parsedDate != null) {
|
||||
_checkInController.text = DateFormat('dd-MM-yyyy').format(parsedDate);
|
||||
}
|
||||
|
||||
// final parsedEndDate = DateTime.tryParse(flightLastTripDateNotifier.value ?? '');
|
||||
final parsedEndDate = DateFormat("dd-MM-yyyy")
|
||||
.parse(flightLastTripDateNotifier.value ?? '');
|
||||
final parsedEndDate = DateFormat(
|
||||
"dd-MM-yyyy",
|
||||
).parse(flightLastTripDateNotifier.value ?? '');
|
||||
|
||||
if (parsedEndDate != null) {
|
||||
// _checkOutController.text = DateFormat('dd-MM-yyyy').format(parsedEndDate);
|
||||
|
||||
_checkOutController.text =
|
||||
DateFormat('dd-MM-yyyy').format(parsedEndDate);
|
||||
_checkOutController.text = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).format(parsedEndDate);
|
||||
}
|
||||
|
||||
// ✅ Check and set default times if empty
|
||||
@ -202,17 +215,16 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
}
|
||||
|
||||
Map<String, String?> getFlightTripDateRange(
|
||||
List<Map<String, dynamic>> flightData) {
|
||||
final allTrips = flightData
|
||||
.expand((flight) => flight['trips'] ?? [])
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.toList();
|
||||
List<Map<String, dynamic>> flightData,
|
||||
) {
|
||||
final allTrips =
|
||||
flightData
|
||||
.expand((flight) => flight['trips'] ?? [])
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.toList();
|
||||
|
||||
if (allTrips.isEmpty) {
|
||||
return {
|
||||
'firstTripDate': null,
|
||||
'lastTripDate': null,
|
||||
};
|
||||
return {'firstTripDate': null, 'lastTripDate': null};
|
||||
}
|
||||
|
||||
allTrips.sort((a, b) {
|
||||
@ -230,7 +242,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
return {
|
||||
'firstTripDate': firstTrip['date'],
|
||||
'lastTripDate': lastTrip['date'],
|
||||
'firstToDestination': firstTripToDestination['to_place']
|
||||
'firstToDestination': firstTripToDestination['to_place'],
|
||||
};
|
||||
}
|
||||
|
||||
@ -244,7 +256,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
"checkin_date",
|
||||
"checkin_time",
|
||||
"checkout_date",
|
||||
"checkout_time"
|
||||
"checkout_time",
|
||||
];
|
||||
|
||||
// Check validation for each field
|
||||
@ -284,8 +296,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
checkOutTime.toString().isNotEmpty) {
|
||||
try {
|
||||
final checkInDateTime = formatTime.parse("$checkIn $checkInTime");
|
||||
final checkOutDateTime =
|
||||
formatTime.parse("$checkOut $checkOutTime");
|
||||
final checkOutDateTime = formatTime.parse(
|
||||
"$checkOut $checkOutTime",
|
||||
);
|
||||
|
||||
if (!checkOutDateTime.isAfter(checkInDateTime)) {
|
||||
errorMessages["checkout_time"] =
|
||||
@ -359,60 +372,51 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isMobile = sizingInfo.isMobile;
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isMobile = sizingInfo.isMobile;
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Container(
|
||||
// color: Color(0xFFF4F4FB),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(28.0),
|
||||
child: Center(
|
||||
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
||||
return Container(
|
||||
// color: Color(0xFFF4F4FB),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(28.0),
|
||||
child: Center(
|
||||
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildAccomadtionForm(isDesktop) {
|
||||
return [
|
||||
isDesktop
|
||||
? Row(
|
||||
children: _buildFirstRow(isDesktop),
|
||||
)
|
||||
: Column(
|
||||
children: _buildFirstRow(isDesktop),
|
||||
),
|
||||
? Row(children: _buildFirstRow(isDesktop))
|
||||
: Column(children: _buildFirstRow(isDesktop)),
|
||||
|
||||
SizedBox(height: 10), // Spacing between first and second row
|
||||
isDesktop
|
||||
? Row(
|
||||
children: _buildSecondRow(isDesktop),
|
||||
)
|
||||
: Column(
|
||||
children: _buildSecondRow(isDesktop),
|
||||
),
|
||||
? Row(children: _buildSecondRow(isDesktop))
|
||||
: Column(children: _buildSecondRow(isDesktop)),
|
||||
|
||||
SizedBox(height: 10),
|
||||
|
||||
isDesktop
|
||||
? Row(
|
||||
children: _buildThirdRow(isDesktop),
|
||||
)
|
||||
: Column(
|
||||
children: _buildThirdRow(isDesktop),
|
||||
),
|
||||
? Row(children: _buildThirdRow(isDesktop))
|
||||
: Column(children: _buildThirdRow(isDesktop)),
|
||||
];
|
||||
}
|
||||
|
||||
@ -432,24 +436,25 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Destination *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _destinationFocused,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
width:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
@ -475,29 +480,26 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Hotel Name *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _isHotelNameFocused,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
width:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
@ -583,18 +585,61 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
initialTime: _selectedCheckInTime ?? TimeOfDay.now(),
|
||||
);
|
||||
|
||||
if (pickedTime != null && pickedTime != _selectedCheckInTime) {
|
||||
if (pickedTime != null) {
|
||||
final now = DateTime.now();
|
||||
|
||||
// Parse the selected date
|
||||
final dateText = _checkInController.text ?? "";
|
||||
final selectedDate = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).parse(dateText); // or 'yyyy-MM-dd' depending on your format
|
||||
|
||||
final selectedDateTime = DateTime(
|
||||
selectedDate.year,
|
||||
selectedDate.month,
|
||||
selectedDate.day,
|
||||
pickedTime.hour,
|
||||
pickedTime.minute,
|
||||
);
|
||||
|
||||
// ✅ Only validate past time if date is today
|
||||
final isToday =
|
||||
selectedDate.year == now.year &&
|
||||
selectedDate.month == now.month &&
|
||||
selectedDate.day == now.day;
|
||||
|
||||
bool isPastTime = selectedDateTime.isBefore(now);
|
||||
|
||||
if (isToday && isPastTime) {
|
||||
setState(() {
|
||||
errorMessages["checkin_time"] = "You can't select a past time.";
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ Valid time selection
|
||||
setState(() {
|
||||
_selectedCheckInTime = pickedTime;
|
||||
// Formatting time to HH:mm (24-hour format)
|
||||
final now = DateTime.now();
|
||||
final formattedTime = DateFormat('HH:mm').format(
|
||||
DateTime(now.year, now.month, now.day, pickedTime.hour,
|
||||
pickedTime.minute),
|
||||
);
|
||||
|
||||
final formattedTime = DateFormat('HH:mm').format(selectedDateTime);
|
||||
_checkInTimeController.text = formattedTime;
|
||||
// errorMessages["time_$index"] = ""; // clear previous error
|
||||
errorMessages.remove("checkin_time");
|
||||
});
|
||||
}
|
||||
|
||||
// if (pickedTime != null && pickedTime != _selectedCheckInTime) {
|
||||
// setState(() {
|
||||
// _selectedCheckInTime = pickedTime;
|
||||
// // Formatting time to HH:mm (24-hour format)
|
||||
// final now = DateTime.now();
|
||||
// final formattedTime = DateFormat('HH:mm').format(
|
||||
// DateTime(now.year, now.month, now.day, pickedTime.hour,
|
||||
// pickedTime.minute),
|
||||
// );
|
||||
// _checkInTimeController.text = formattedTime;
|
||||
// });
|
||||
// }
|
||||
}
|
||||
//-------------------------------Check-In End
|
||||
|
||||
@ -647,10 +692,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
// : firstDate;
|
||||
|
||||
DateTime firstDate = checkInDate;
|
||||
DateTime initialDate = _selectedCheckOutDate != null &&
|
||||
_selectedCheckOutDate!.isAfter(firstDate)
|
||||
? _selectedCheckOutDate!
|
||||
: firstDate;
|
||||
DateTime initialDate =
|
||||
_selectedCheckOutDate != null &&
|
||||
_selectedCheckOutDate!.isAfter(firstDate)
|
||||
? _selectedCheckOutDate!
|
||||
: firstDate;
|
||||
|
||||
final pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
@ -662,8 +708,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
||||
setState(() {
|
||||
_selectedCheckOutDate = pickedDate;
|
||||
_checkOutController.text =
|
||||
DateFormat('dd-MM-yyyy').format(pickedDate);
|
||||
_checkOutController.text = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).format(pickedDate);
|
||||
errorMessages.remove("checkout_date");
|
||||
});
|
||||
}
|
||||
@ -681,8 +728,13 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
// Formatting time to HH:mm (24-hour format)
|
||||
final now = DateTime.now();
|
||||
final formattedTime = DateFormat('HH:mm').format(
|
||||
DateTime(now.year, now.month, now.day, pickedTime.hour,
|
||||
pickedTime.minute),
|
||||
DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
pickedTime.hour,
|
||||
pickedTime.minute,
|
||||
),
|
||||
);
|
||||
_checkOutTimeController.text = formattedTime;
|
||||
errorMessages.remove("checkout_time");
|
||||
@ -697,9 +749,10 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
Text(
|
||||
"Check-in *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -720,8 +773,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon: Icon(Icons.calendar_today,
|
||||
size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -737,21 +793,17 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Time (Check-in) *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -760,7 +812,10 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
onTap: () => _selectCheckInTime(context),
|
||||
onTap: () {
|
||||
_checkInTimeController.text = "";
|
||||
_selectCheckInTime(context);
|
||||
},
|
||||
child: AbsorbPointer(
|
||||
child: TextField(
|
||||
focusNode: _checkInTimeFocusNode,
|
||||
@ -772,8 +827,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon:
|
||||
Icon(Icons.access_time, size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.access_time,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -789,21 +847,17 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Check-out*",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -824,8 +878,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon: Icon(Icons.calendar_today,
|
||||
size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -841,21 +898,17 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Time (Check-out) *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldItnerarySubWrapper(
|
||||
@ -876,8 +929,11 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon:
|
||||
Icon(Icons.access_time, size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.access_time,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -904,17 +960,19 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
Text(
|
||||
"Comments",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
width:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
@ -934,9 +992,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
],
|
||||
),
|
||||
if (isDesktop) Spacer(),
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
@ -957,9 +1013,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.grey[400], // Light grey color
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
child: Text(
|
||||
@ -968,7 +1022,6 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10), // Space between buttons
|
||||
|
||||
// Save Changes Button
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
@ -976,9 +1029,7 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
child: Text(
|
||||
|
||||
@ -568,9 +568,9 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
}
|
||||
|
||||
bool validateFields() {
|
||||
errorMessages.clear(); // Reset errors
|
||||
// errorMessages.clear(); // Reset errors
|
||||
|
||||
rowCount = 1; // Default row count for One-way
|
||||
rowCount = 1; // Default row count for One-way
|
||||
if (selectedTripType == "Roundtrip") {
|
||||
rowCount = 2; // Fixed for Roundtrip
|
||||
} else if (selectedTripType == "Multitrip") {
|
||||
@ -594,23 +594,21 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
// errorMessages["to_place_$i"] = "Change Destination";
|
||||
// }
|
||||
|
||||
|
||||
if (selectedTo[i] == null) {
|
||||
errorMessages["to_place_$i"] = "Required";
|
||||
print("Error: to_place_$i -> Required (selectedTo[$i] is null)");
|
||||
} else if (selectedFrom[i] == selectedTo[i]) {
|
||||
|
||||
if(selectedTripType == "Roundtrip"){
|
||||
if (selectedTripType == "Roundtrip") {
|
||||
errorMessages["to_place_1"] = "Change Destination";
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
errorMessages["to_place_$i"] = "Change Destination";
|
||||
}
|
||||
|
||||
print("Error: to_place_$i -> Change Destination (selectedFrom[$i] == selectedTo[$i])");
|
||||
print(
|
||||
"Error: to_place_$i -> Change Destination (selectedFrom[$i] == selectedTo[$i])",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// if (textControllers["_to${i}Controller"]?.text.trim().isEmpty ?? true) {
|
||||
// errorMessages["to_place_$i"] = "Required";
|
||||
// }
|
||||
@ -620,13 +618,8 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
if (textControllers["_time${i}Controller"]?.text.trim().isEmpty ?? true) {
|
||||
errorMessages["time_$i"] = "Required";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
setState(() {}); // Update UI to show error messages
|
||||
|
||||
return errorMessages
|
||||
@ -1238,41 +1231,73 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
initialTime: _selectedCheckOutTime ?? TimeOfDay.now(),
|
||||
);
|
||||
|
||||
if (pickedTime != null && pickedTime != _selectedCheckOutTime) {
|
||||
if (pickedTime != null) {
|
||||
final now = DateTime.now();
|
||||
|
||||
// Parse the selected date
|
||||
final dateText = textControllers["_date${index}Controller"]?.text ?? "";
|
||||
final selectedDate = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).parse(dateText); // or 'yyyy-MM-dd' depending on your format
|
||||
|
||||
final selectedDateTime = DateTime(
|
||||
selectedDate.year,
|
||||
selectedDate.month,
|
||||
selectedDate.day,
|
||||
pickedTime.hour,
|
||||
pickedTime.minute,
|
||||
);
|
||||
|
||||
// ✅ Only validate past time if date is today
|
||||
final isToday =
|
||||
selectedDate.year == now.year &&
|
||||
selectedDate.month == now.month &&
|
||||
selectedDate.day == now.day;
|
||||
|
||||
bool isPastTime = selectedDateTime.isBefore(now);
|
||||
|
||||
if (isToday && isPastTime) {
|
||||
setState(() {
|
||||
errorMessages["time_$index"] = "You can't select a past time.";
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ Valid time selection
|
||||
setState(() {
|
||||
_selectedCheckOutTime = pickedTime;
|
||||
// Formatting time to HH:mm (24-hour format)
|
||||
final now = DateTime.now();
|
||||
final formattedTime = DateFormat('HH:mm').format(
|
||||
DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
pickedTime.hour,
|
||||
pickedTime.minute,
|
||||
),
|
||||
);
|
||||
// _timeController.text = formattedTime;
|
||||
textControllers["_time${index}Controller"]?.text = formattedTime;
|
||||
|
||||
onPicked();
|
||||
final formattedTime = DateFormat('HH:mm').format(selectedDateTime);
|
||||
textControllers["_time${index}Controller"]?.text = formattedTime;
|
||||
// errorMessages["time_$index"] = ""; // clear previous error
|
||||
errorMessages.remove("time_$index");
|
||||
onPicked(); // Trigger callback
|
||||
});
|
||||
}
|
||||
|
||||
// if (pickedTime != null && pickedTime != _selectedCheckOutTime) {
|
||||
// setState(() {
|
||||
// _selectedCheckOutTime = pickedTime;
|
||||
// // Formatting time to HH:mm (24-hour format)
|
||||
// final now = DateTime.now();
|
||||
// final formattedTime = DateFormat('HH:mm').format(
|
||||
// DateTime(
|
||||
// now.year,
|
||||
// now.month,
|
||||
// now.day,
|
||||
// pickedTime.hour,
|
||||
// pickedTime.minute,
|
||||
// ),
|
||||
// );
|
||||
//
|
||||
// // _timeController.text = formattedTime;
|
||||
// textControllers["_time${index}Controller"]?.text = formattedTime;
|
||||
//
|
||||
// onPicked();
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
// 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
|
||||
// };
|
||||
|
||||
// // Extract only country codes for processing
|
||||
// countryCodes = countryMap.keys.toList();
|
||||
//
|
||||
// selectedCountry ??= null;
|
||||
|
||||
return [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -1297,7 +1322,8 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
isCountryLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: DropdownSearch<String>(
|
||||
enabled: !(selectedTripType == "Roundtrip" && index == 2),
|
||||
enabled:
|
||||
!(selectedTripType == "Roundtrip" && index == 2),
|
||||
selectedItem:
|
||||
selectedFrom[index] != null
|
||||
? countryMap[selectedFrom[index]]
|
||||
@ -1323,25 +1349,37 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
final airport = parts.length > 1 ? parts[1] : '';
|
||||
|
||||
// Extract city and code from "City (CODE)"
|
||||
final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode);
|
||||
final cityMatch = RegExp(
|
||||
r'^(.*)\s+\(([^)]+)\)$',
|
||||
).firstMatch(cityAndCode);
|
||||
final city = cityMatch?.group(1) ?? '';
|
||||
final code = cityMatch?.group(2) ?? '';
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 6.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
city,
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
code,
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -1380,26 +1418,31 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
dropdownBuilder: (context, selectedItem) {
|
||||
if (selectedItem == null) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,child: const Text("Select", style: TextStyle(fontSize: 12)));
|
||||
}
|
||||
|
||||
final parts = selectedItem.split('\n');
|
||||
final cityAndCode = parts[0];
|
||||
final airport = parts.length > 1 ? parts[1] : '';
|
||||
|
||||
return Align(
|
||||
dropdownBuilder: (context, selectedItem) {
|
||||
if (selectedItem == null) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
cityAndCode ?? "Select",
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text(
|
||||
"Select",
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// dropdownBuilder:
|
||||
final parts = selectedItem.split('\n');
|
||||
final cityAndCode = parts[0];
|
||||
final airport = parts.length > 1 ? parts[1] : '';
|
||||
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
cityAndCode ?? "Select",
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
// dropdownBuilder:
|
||||
// (context, selectedItem) => Align(
|
||||
// alignment: Alignment.centerLeft,
|
||||
// child: Text(
|
||||
@ -1409,6 +1452,7 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
// ),
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
errorMessages.remove("from_place_$index");
|
||||
// selectedFrom[index] = countryMap.entries
|
||||
// .firstWhere((entry) => entry.value == newValue)
|
||||
// .key;
|
||||
@ -1420,13 +1464,11 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
)
|
||||
.key;
|
||||
|
||||
if(selectedTripType == "Roundtrip"){
|
||||
|
||||
if (selectedTripType == "Roundtrip") {
|
||||
print('rounfTo${selectedFrom[index]}');
|
||||
// textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
|
||||
selectedTo[2]= selectedFrom[index]!;
|
||||
selectedTo[2] = selectedFrom[index]!;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
),
|
||||
@ -1477,7 +1519,8 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
isCountryLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: DropdownSearch<String>(
|
||||
enabled: !(selectedTripType == "Roundtrip" && index == 2),
|
||||
enabled:
|
||||
!(selectedTripType == "Roundtrip" && index == 2),
|
||||
selectedItem:
|
||||
selectedTo[index] != null
|
||||
? countryMap[selectedTo[index]]
|
||||
@ -1502,27 +1545,38 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
final cityAndCode = parts[0];
|
||||
final airport = parts.length > 1 ? parts[1] : '';
|
||||
|
||||
|
||||
// Extract city and code from "City (CODE)"
|
||||
final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode);
|
||||
final cityMatch = RegExp(
|
||||
r'^(.*)\s+\(([^)]+)\)$',
|
||||
).firstMatch(cityAndCode);
|
||||
final city = cityMatch?.group(1) ?? '';
|
||||
final code = cityMatch?.group(2) ?? '';
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 6.0,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
city,
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
code,
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -1560,6 +1614,7 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
|
||||
// dropdownBuilder:
|
||||
// (context, selectedItem) => Align(
|
||||
// alignment: Alignment.centerLeft,
|
||||
@ -1568,26 +1623,30 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
// style: TextStyle(fontSize: 12),
|
||||
// ),
|
||||
// ),
|
||||
dropdownBuilder: (context, selectedItem) {
|
||||
if (selectedItem == null) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: const Text(
|
||||
"Select",
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
dropdownBuilder: (context, selectedItem) {
|
||||
if (selectedItem == null) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,child: const Text("Select", style: TextStyle(fontSize: 12)));
|
||||
}
|
||||
final parts = selectedItem.split('\n');
|
||||
final cityAndCode = parts[0];
|
||||
final airport = parts.length > 1 ? parts[1] : '';
|
||||
|
||||
final parts = selectedItem.split('\n');
|
||||
final cityAndCode = parts[0];
|
||||
final airport = parts.length > 1 ? parts[1] : '';
|
||||
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
cityAndCode ?? "Select",
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
);
|
||||
},
|
||||
onChanged: (String? newValue) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
cityAndCode ?? "Select",
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
);
|
||||
},
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
errorMessages.remove("to_place_$index");
|
||||
selectedTo[index] =
|
||||
@ -1599,11 +1658,10 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
|
||||
print(selectedTo[index]);
|
||||
|
||||
if(selectedTripType == "Roundtrip"){
|
||||
|
||||
if (selectedTripType == "Roundtrip") {
|
||||
print('rounfTo${selectedTo[index]}');
|
||||
// textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!;
|
||||
selectedFrom[2]= selectedTo[index]!;
|
||||
selectedFrom[2] = selectedTo[index]!;
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -1612,7 +1670,10 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
),
|
||||
if (errorMessages["to_place_$index"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text( errorMessages["to_place_$index"]! , style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
Text(
|
||||
errorMessages["to_place_$index"]!,
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
@ -1835,6 +1896,7 @@ class FlightScreenState extends State<FlightScreen> {
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
textControllers["_time${index}Controller"]?.text = "";
|
||||
_clearError("time_$index");
|
||||
// validateTimeDifference(index);
|
||||
// _selectCheckOutTime(context);
|
||||
|
||||
@ -15,13 +15,14 @@ class InsuranceScreen extends StatefulWidget {
|
||||
final Map<String, dynamic>? selectedItem;
|
||||
final String? loginUser;
|
||||
|
||||
InsuranceScreen(
|
||||
{required this.onClose,
|
||||
required this.apiData,
|
||||
required this.onSaveInsurance,
|
||||
required this.selectedItem,
|
||||
required this.loginUser,
|
||||
required this.flightData});
|
||||
InsuranceScreen({
|
||||
required this.onClose,
|
||||
required this.apiData,
|
||||
required this.onSaveInsurance,
|
||||
required this.selectedItem,
|
||||
required this.loginUser,
|
||||
required this.flightData,
|
||||
});
|
||||
|
||||
@override
|
||||
_InsuranceScreenState createState() => _InsuranceScreenState();
|
||||
@ -45,7 +46,8 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
late TextEditingController _tripTypeController = TextEditingController();
|
||||
late TextEditingController _startdateController = TextEditingController();
|
||||
late TextEditingController _endDateController = TextEditingController();
|
||||
late TextEditingController _insuranceCommentsController = TextEditingController();
|
||||
late TextEditingController _insuranceCommentsController =
|
||||
TextEditingController();
|
||||
late TextEditingController _nomineeController = TextEditingController();
|
||||
|
||||
bool _isHotelNameFocused = false;
|
||||
@ -64,7 +66,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
"start_date": _startdateController.text,
|
||||
"end_date": _endDateController.text,
|
||||
"comments": _insuranceCommentsController.text,
|
||||
"nominee_name" : _nomineeController.text,
|
||||
"nominee_name": _nomineeController.text,
|
||||
"created_by": widget.loginUser,
|
||||
"updated_by": widget.loginUser,
|
||||
};
|
||||
@ -108,14 +110,18 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
});
|
||||
});
|
||||
|
||||
_insuranceCommentsController =
|
||||
TextEditingController(text: widget.selectedItem?["comments"] ?? "");
|
||||
_startdateController =
|
||||
TextEditingController(text: widget.selectedItem?["start_date"] ?? "");
|
||||
_endDateController =
|
||||
TextEditingController(text: widget.selectedItem?['end_date'] ?? "");
|
||||
_nomineeController =
|
||||
TextEditingController(text: widget.selectedItem?['nominee_name'] ?? "");
|
||||
_insuranceCommentsController = TextEditingController(
|
||||
text: widget.selectedItem?["comments"] ?? "",
|
||||
);
|
||||
_startdateController = TextEditingController(
|
||||
text: widget.selectedItem?["start_date"] ?? "",
|
||||
);
|
||||
_endDateController = TextEditingController(
|
||||
text: widget.selectedItem?['end_date'] ?? "",
|
||||
);
|
||||
_nomineeController = TextEditingController(
|
||||
text: widget.selectedItem?['nominee_name'] ?? "",
|
||||
);
|
||||
|
||||
// Set the selected value if available
|
||||
if (widget.selectedItem != null &&
|
||||
@ -135,17 +141,20 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
// ✅ Only set controller after value is updated
|
||||
// final parsedDate =
|
||||
// DateTime.tryParse(flightFirstTripDateNotifier.value ?? '');
|
||||
final parsedDate = DateFormat("dd-MM-yyyy")
|
||||
.parse(flightFirstTripDateNotifier.value ?? '');
|
||||
final parsedDate = DateFormat(
|
||||
"dd-MM-yyyy",
|
||||
).parse(flightFirstTripDateNotifier.value ?? '');
|
||||
if (parsedDate != null) {
|
||||
_startdateController.text = DateFormat('dd-MM-yyyy').format(parsedDate);
|
||||
}
|
||||
|
||||
final parsedEndDate = DateFormat("dd-MM-yyyy")
|
||||
.parse(flightLastTripDateNotifier.value ?? '');
|
||||
final parsedEndDate = DateFormat(
|
||||
"dd-MM-yyyy",
|
||||
).parse(flightLastTripDateNotifier.value ?? '');
|
||||
if (parsedEndDate != null) {
|
||||
_endDateController.text =
|
||||
DateFormat('dd-MM-yyyy').format(parsedEndDate);
|
||||
_endDateController.text = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).format(parsedEndDate);
|
||||
|
||||
print("parsedDate");
|
||||
print(parsedDate);
|
||||
@ -156,17 +165,16 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
}
|
||||
|
||||
Map<String, String?> getFlightTripDateRange(
|
||||
List<Map<String, dynamic>> flightData) {
|
||||
final allTrips = flightData
|
||||
.expand((flight) => flight['trips'] ?? [])
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.toList();
|
||||
List<Map<String, dynamic>> flightData,
|
||||
) {
|
||||
final allTrips =
|
||||
flightData
|
||||
.expand((flight) => flight['trips'] ?? [])
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.toList();
|
||||
|
||||
if (allTrips.isEmpty) {
|
||||
return {
|
||||
'firstTripDate': null,
|
||||
'lastTripDate': null,
|
||||
};
|
||||
return {'firstTripDate': null, 'lastTripDate': null};
|
||||
}
|
||||
|
||||
allTrips.sort((a, b) {
|
||||
@ -199,7 +207,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
List<String> requiredFields = [
|
||||
"type_of_insurance",
|
||||
"start_date",
|
||||
"end_date"
|
||||
"end_date",
|
||||
];
|
||||
|
||||
// Check validation for each field
|
||||
@ -267,30 +275,33 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isMobile = sizingInfo.isMobile;
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
return ResponsiveBuilder(
|
||||
builder: (context, sizingInfo) {
|
||||
bool isMobile = sizingInfo.isMobile;
|
||||
bool isDesktop =
|
||||
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Container(
|
||||
// color: Color(0xFFF4F4FB),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(28.0),
|
||||
child: Center(
|
||||
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
||||
return Container(
|
||||
// color: Color(0xFFF4F4FB),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 30.0),
|
||||
child: Center(
|
||||
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
||||
@ -303,7 +314,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
|
||||
List<List<Widget>> rowBuilders = [
|
||||
// _builClassType(isDesktop),
|
||||
_buildSecondRow(isDesktop)
|
||||
_buildSecondRow(isDesktop),
|
||||
];
|
||||
|
||||
return [
|
||||
@ -318,51 +329,52 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildFirstRow(isDesktop) {
|
||||
return [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Insurance Type", // not in use
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
isDesktop
|
||||
? Row(children: _buildTripType(isDesktop))
|
||||
: Column(children: _buildTripType(isDesktop))
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
];
|
||||
}
|
||||
// List<Widget> _buildFirstRow(isDesktop) {
|
||||
// return [
|
||||
// Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Insurance Type", // not in use
|
||||
// style: GoogleFonts.poppins(
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.w500,
|
||||
// color: Color(0xFF575A74),
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(height: 5),
|
||||
// isDesktop
|
||||
// ? Row(children: _buildTripType(isDesktop))
|
||||
// : Column(children: _buildTripType(isDesktop)),
|
||||
// ],
|
||||
// ),
|
||||
// if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
// ];
|
||||
// }
|
||||
|
||||
List<Widget> _buildTripType(bool isDesktop) {
|
||||
List<dynamic> purposeList =
|
||||
widget.apiData?['insurance_type_of_insurance'] ?? [];
|
||||
// selectedInsuranceType = purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
||||
|
||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||
.map((item) => DropdownMenuItem<String>(
|
||||
value: item['dropdown_key'],
|
||||
child: Text(item['dropdown_value']),
|
||||
))
|
||||
.toList();
|
||||
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)),
|
||||
child: Text(
|
||||
"No options available",
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -375,9 +387,10 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _isHotelNameFocused,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
width:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: DropdownButtonFormField<String>(
|
||||
@ -386,21 +399,23 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
), // Proper padding
|
||||
),
|
||||
onChanged: purposeList.isNotEmpty
|
||||
? (newValue) {
|
||||
setState(() {
|
||||
selectedInsuranceType = newValue;
|
||||
if (selectedInsuranceType!.isNotEmpty) {
|
||||
errorMessages.remove("type_of_insurance");
|
||||
}
|
||||
});
|
||||
onChanged:
|
||||
purposeList.isNotEmpty
|
||||
? (newValue) {
|
||||
setState(() {
|
||||
selectedInsuranceType = newValue;
|
||||
if (selectedInsuranceType!.isNotEmpty) {
|
||||
errorMessages.remove("type_of_insurance");
|
||||
}
|
||||
});
|
||||
|
||||
print(selectedInsuranceType);
|
||||
}
|
||||
: null,
|
||||
print(selectedInsuranceType);
|
||||
}
|
||||
: null,
|
||||
|
||||
items: dropdownItems,
|
||||
),
|
||||
@ -409,16 +424,17 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
List<Widget> _buildInsuranceTypeDropdown(bool isDesktop) {
|
||||
// List<dynamic> purposeList = widget.apiData?['insurance_type_of_insurance'] ?? [];
|
||||
List<Map<String, dynamic>> purposeList = (widget.apiData?['insurance_type_of_insurance'] as List<dynamic>?)
|
||||
?.map((e) => Map<String, dynamic>.from(e as Map))
|
||||
.toList() ?? [];
|
||||
List<Map<String, dynamic>> purposeList =
|
||||
(widget.apiData?['insurance_type_of_insurance'] as List<dynamic>?)
|
||||
?.map((e) => Map<String, dynamic>.from(e as Map))
|
||||
.toList() ??
|
||||
[];
|
||||
|
||||
// Find selected item object based on key
|
||||
Map<String, dynamic>? selectedItem = purposeList.firstWhere(
|
||||
(item) => item['dropdown_key'] == selectedInsuranceType,
|
||||
(item) => item['dropdown_key'] == selectedInsuranceType,
|
||||
orElse: () => {},
|
||||
);
|
||||
|
||||
@ -476,17 +492,20 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
},
|
||||
selectedItem: selectedItem!.isNotEmpty ? selectedItem : null,
|
||||
itemAsString: (item) => item['dropdown_value'] ?? '',
|
||||
onChanged: purposeList.isNotEmpty
|
||||
? (Map<String, dynamic>? newItem) {
|
||||
if (newItem != null) {
|
||||
setState(() {
|
||||
selectedInsuranceType = newItem['dropdown_key'];
|
||||
errorMessages.remove("type_of_insurance");
|
||||
});
|
||||
print("Selected Insurance Type: $selectedInsuranceType");
|
||||
}
|
||||
}
|
||||
: null,
|
||||
onChanged:
|
||||
purposeList.isNotEmpty
|
||||
? (Map<String, dynamic>? newItem) {
|
||||
if (newItem != null) {
|
||||
setState(() {
|
||||
selectedInsuranceType = newItem['dropdown_key'];
|
||||
errorMessages.remove("type_of_insurance");
|
||||
});
|
||||
print(
|
||||
"Selected Insurance Type: $selectedInsuranceType",
|
||||
);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
items: purposeList,
|
||||
),
|
||||
),
|
||||
@ -494,26 +513,29 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<Widget> _buildSecondRow(bool isDesktop) {
|
||||
List<dynamic> purposeList =
|
||||
widget.apiData?['insurance_type_of_insurance'] ?? [];
|
||||
// selectedInsuranceType = purposeList.isNotEmpty ? purposeList.first['dropdown_value'] : null;
|
||||
|
||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
||||
.map((item) => DropdownMenuItem<String>(
|
||||
value: item['dropdown_key'],
|
||||
child: Text(item['dropdown_value']),
|
||||
))
|
||||
.toList();
|
||||
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)),
|
||||
child: Text(
|
||||
"No options available",
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -569,8 +591,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
||||
setState(() {
|
||||
_selectedCheckOutDate = pickedDate;
|
||||
_startdateController.text =
|
||||
DateFormat('dd-MM-yyyy').format(pickedDate);
|
||||
_startdateController.text = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).format(pickedDate);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -594,10 +617,11 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
// : firstDate;
|
||||
|
||||
DateTime firstDate = checkInDate;
|
||||
DateTime initialDate = _selectedCheckOutDate != null &&
|
||||
_selectedCheckOutDate!.isAfter(firstDate)
|
||||
? _selectedCheckOutDate!
|
||||
: firstDate;
|
||||
DateTime initialDate =
|
||||
_selectedCheckOutDate != null &&
|
||||
_selectedCheckOutDate!.isAfter(firstDate)
|
||||
? _selectedCheckOutDate!
|
||||
: firstDate;
|
||||
|
||||
final pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
@ -624,7 +648,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -643,7 +666,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _isHotelNameFocused,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.17 : null,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null,
|
||||
child: SizedBox(
|
||||
height: 35,
|
||||
width: double.infinity,
|
||||
@ -653,53 +676,56 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 5,
|
||||
),
|
||||
),
|
||||
hint: Text(
|
||||
"Select ",
|
||||
style: GoogleFonts.poppins(color: Colors.grey, fontSize: 13),
|
||||
),
|
||||
items: purposeList.map<DropdownMenuItem<String>>((item) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: item['dropdown_key'],
|
||||
child: Text(
|
||||
item['dropdown_value'] ?? '',
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: purposeList.isNotEmpty
|
||||
? (String? newValue) {
|
||||
setState(() {
|
||||
selectedInsuranceType = newValue;
|
||||
if ((selectedInsuranceType ?? '').isNotEmpty) {
|
||||
errorMessages.remove("type_of_insurance");
|
||||
}
|
||||
});
|
||||
print("Selected Insurance Type: $selectedInsuranceType");
|
||||
}
|
||||
: null,
|
||||
items:
|
||||
purposeList.map<DropdownMenuItem<String>>((item) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: item['dropdown_key'],
|
||||
child: Text(
|
||||
item['dropdown_value'] ?? '',
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged:
|
||||
purposeList.isNotEmpty
|
||||
? (String? newValue) {
|
||||
setState(() {
|
||||
selectedInsuranceType = newValue;
|
||||
if ((selectedInsuranceType ?? '').isNotEmpty) {
|
||||
errorMessages.remove("type_of_insurance");
|
||||
}
|
||||
});
|
||||
print(
|
||||
"Selected Insurance Type: $selectedInsuranceType",
|
||||
);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Nominee",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
@ -726,27 +752,23 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Start Date *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _dateFocus,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
@ -754,8 +776,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
await _selectCheckOutDate(context);
|
||||
if (_startdateController.text.isNotEmpty) {
|
||||
setState(() {
|
||||
errorMessages
|
||||
.remove("start_date"); // Removes the key completely
|
||||
errorMessages.remove(
|
||||
"start_date",
|
||||
); // Removes the key completely
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -770,8 +793,11 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon: Icon(Icons.calendar_today,
|
||||
size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -780,34 +806,27 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
),
|
||||
if (errorMessages["start_date"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text(
|
||||
"Required",
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"End Date *",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _dateFocus,
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null,
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
@ -843,8 +862,11 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
suffixIcon: Icon(Icons.calendar_today,
|
||||
size: 16, color: Colors.grey),
|
||||
suffixIcon: Icon(
|
||||
Icons.calendar_today,
|
||||
size: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -861,12 +883,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
Spacer()
|
||||
else
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||
];
|
||||
}
|
||||
|
||||
@ -878,17 +895,19 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
Text(
|
||||
"Comments",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldWrapper(
|
||||
isFocused: _commentsFocus, // Dropdown doesn't use focus
|
||||
isDesktop: isDesktop,
|
||||
width: isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.34
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
width:
|
||||
isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.31
|
||||
: MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
@ -908,9 +927,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
],
|
||||
),
|
||||
if (isDesktop) Spacer(),
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
@ -931,9 +948,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.grey[400], // Light grey color
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
child: Text(
|
||||
@ -942,7 +957,6 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10), // Space between buttons
|
||||
|
||||
// Save Changes Button
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
@ -950,9 +964,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
child: Text(
|
||||
|
||||
@ -480,23 +480,66 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
initialTime: _selectedCheckOutTime ?? TimeOfDay.now(),
|
||||
);
|
||||
|
||||
if (pickedTime != null && pickedTime != _selectedCheckOutTime) {
|
||||
if (pickedTime != null) {
|
||||
final now = DateTime.now();
|
||||
|
||||
// Parse the selected date
|
||||
final dateText = _dateController.text ?? "";
|
||||
final selectedDate = DateFormat(
|
||||
'dd-MM-yyyy',
|
||||
).parse(dateText); // or 'yyyy-MM-dd' depending on your format
|
||||
|
||||
final selectedDateTime = DateTime(
|
||||
selectedDate.year,
|
||||
selectedDate.month,
|
||||
selectedDate.day,
|
||||
pickedTime.hour,
|
||||
pickedTime.minute,
|
||||
);
|
||||
|
||||
// ✅ Only validate past time if date is today
|
||||
final isToday =
|
||||
selectedDate.year == now.year &&
|
||||
selectedDate.month == now.month &&
|
||||
selectedDate.day == now.day;
|
||||
|
||||
bool isPastTime = selectedDateTime.isBefore(now);
|
||||
|
||||
if (isToday && isPastTime) {
|
||||
setState(() {
|
||||
errorMessages["time"] = "You can't select a past time.";
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ Valid time selection
|
||||
setState(() {
|
||||
_selectedCheckOutTime = pickedTime;
|
||||
// Formatting time to HH:mm (24-hour format)
|
||||
final now = DateTime.now();
|
||||
final formattedTime = DateFormat('HH:mm').format(
|
||||
DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
pickedTime.hour,
|
||||
pickedTime.minute,
|
||||
),
|
||||
);
|
||||
|
||||
final formattedTime = DateFormat('HH:mm').format(selectedDateTime);
|
||||
_timeController.text = formattedTime;
|
||||
// errorMessages["time_$index"] = ""; // clear previous error
|
||||
errorMessages.remove("time");
|
||||
});
|
||||
}
|
||||
|
||||
// if (pickedTime != null && pickedTime != _selectedCheckOutTime) {
|
||||
// setState(() {
|
||||
// _selectedCheckOutTime = pickedTime;
|
||||
// // Formatting time to HH:mm (24-hour format)
|
||||
// final now = DateTime.now();
|
||||
// final formattedTime = DateFormat('HH:mm').format(
|
||||
// DateTime(
|
||||
// now.year,
|
||||
// now.month,
|
||||
// now.day,
|
||||
// pickedTime.hour,
|
||||
// pickedTime.minute,
|
||||
// ),
|
||||
// );
|
||||
// _timeController.text = formattedTime;
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
@ -831,7 +874,10 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
onTap: () => _selectCheckOutTime(context),
|
||||
onTap: () {
|
||||
_timeController.text = "";
|
||||
_selectCheckOutTime(context);
|
||||
},
|
||||
child: AbsorbPointer(
|
||||
child: TextField(
|
||||
focusNode: _timeFocusNode,
|
||||
@ -856,7 +902,10 @@ class _TrainScreenState extends State<TrainScreen> {
|
||||
),
|
||||
if (errorMessages["time"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
||||
Text(
|
||||
errorMessages["time"]!,
|
||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
||||
@ -3008,8 +3008,9 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
labelText: "Trip Name *",
|
||||
labelStyle: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.grey,
|
||||
// color: Color(0xFF575A74),
|
||||
),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
|
||||
20
pubspec.lock
20
pubspec.lock
@ -21,10 +21,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
version: "2.13.0"
|
||||
bcrypt:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -149,10 +149,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -465,18 +465,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
version: "0.20.2"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.8"
|
||||
version: "10.0.9"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1014,10 +1014,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
version: "15.0.0"
|
||||
vsc_quill_delta_to_html:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@ -44,7 +44,7 @@ dependencies:
|
||||
responsive_builder: ^0.7.1
|
||||
shared_preferences: ^2.5.2
|
||||
easy_stepper: ^0.8.5+1
|
||||
intl: ^0.19.0
|
||||
intl: ^0.20.2
|
||||
dropdown_search: ^5.0.6
|
||||
file_picker: ^10.0.0
|
||||
bcrypt: ^1.1.3
|
||||
|
||||
Loading…
Reference in New Issue
Block a user