1414 lines
48 KiB
Dart
1414 lines
48 KiB
Dart
import 'package:dropdown_search/dropdown_search.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:responsive_builder/responsive_builder.dart';
|
|
|
|
import '../../utils/auth_utils.dart';
|
|
import '../../widgets/custom_text_field.dart';
|
|
import '../../widgets/custom_text_itnerary_sub.dart';
|
|
|
|
class InsuranceScreen extends StatefulWidget {
|
|
final List<Map<String, dynamic>> flightData;
|
|
final Map<String, dynamic>? apiData;
|
|
final Function(String, bool) onClose;
|
|
final Function(Map<String, dynamic>) onSaveInsurance;
|
|
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,
|
|
});
|
|
|
|
@override
|
|
_InsuranceScreenState createState() => _InsuranceScreenState();
|
|
}
|
|
|
|
class _InsuranceScreenState extends State<InsuranceScreen> {
|
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
|
|
|
Map<String, String?> selectedValues = {};
|
|
|
|
late ValueNotifier<String?> flightFirstTripDateNotifier;
|
|
late ValueNotifier<String?> flightLastTripDateNotifier;
|
|
|
|
final FocusNode _tripTypeFocusNode = FocusNode();
|
|
final FocusNode _hotelNameFocusNode = FocusNode();
|
|
final FocusNode _startDateFocusNode = FocusNode();
|
|
final FocusNode _endDateFocusNode = FocusNode();
|
|
final FocusNode _commentsFocusNode = FocusNode();
|
|
final FocusNode _nomineeFocusNode = FocusNode();
|
|
|
|
late TextEditingController _tripTypeController = TextEditingController();
|
|
late TextEditingController _startDateController = TextEditingController();
|
|
late TextEditingController _dateOfBirthController = TextEditingController();
|
|
late TextEditingController _endDateController = TextEditingController();
|
|
late TextEditingController _insuranceCommentsController =
|
|
TextEditingController();
|
|
late TextEditingController _nomineeController = TextEditingController();
|
|
late TextEditingController _nomineerelationController =
|
|
TextEditingController();
|
|
|
|
Color layoutColor = Colors.grey;
|
|
|
|
bool _isHotelNameFocused = false;
|
|
bool _startDateFocus = false;
|
|
bool _endDateFocus = false;
|
|
bool _commentsFocus = false;
|
|
bool _nomineeFocus = false;
|
|
|
|
String? selectedTripType;
|
|
String? selectedInsuranceType;
|
|
|
|
Map<String, String> errorMessages = {};
|
|
Map<String, FocusNode> focusNodes = {};
|
|
Map<String, bool> focusStates = {};
|
|
|
|
List<String> dataHeader = [
|
|
"type_of_insurance",
|
|
"start_date",
|
|
"end_date",
|
|
"comments",
|
|
"nominee_name",
|
|
"nominee_dob",
|
|
"nominee_relationship",
|
|
];
|
|
|
|
Map<String, dynamic> get InsuranceData {
|
|
Map<String, dynamic> data = {
|
|
"type_of_insurance": selectedInsuranceType,
|
|
"start_date": _startDateController.text,
|
|
|
|
"end_date": _endDateController.text,
|
|
"comments": _insuranceCommentsController.text,
|
|
"nominee_name": _nomineeController.text,
|
|
"nominee_dob": _dateOfBirthController.text,
|
|
"nominee_relationship": _nomineerelationController.text,
|
|
"created_by": widget.loginUser,
|
|
"updated_by": widget.loginUser,
|
|
};
|
|
|
|
if (widget.selectedItem != null) {
|
|
if (widget.selectedItem?["indx"] != null &&
|
|
widget.selectedItem?["indx"] != 0) {
|
|
data["indx"] = widget.selectedItem!["indx"];
|
|
} else if (widget.selectedItem?["insurance_id"] != null &&
|
|
widget.selectedItem?["insurance_id"] != 0) {
|
|
data["insurance_id"] = widget.selectedItem!["insurance_id"];
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
loadInitialData();
|
|
});
|
|
focusNodes.clear();
|
|
focusStates.clear();
|
|
|
|
// Initialize fields dynamically
|
|
for (var field in dataHeader) {
|
|
focusNodes["${field}FocusNode"] = FocusNode();
|
|
focusStates["${field}Focused"] = false;
|
|
}
|
|
|
|
for (var key in focusNodes.keys) {
|
|
_addFocusListener(focusNodes[key]!, (focus) {
|
|
setState(() {
|
|
focusStates[key.replaceFirst("FocusNode", "Focused")] = focus;
|
|
});
|
|
});
|
|
}
|
|
print("Focus Nodes Keys: ${focusNodes.keys.toList()}");
|
|
print("Focus States Keys: ${focusStates.keys.toList()}");
|
|
|
|
_insuranceCommentsController = TextEditingController(
|
|
text: widget.selectedItem?["comments"] ?? "",
|
|
);
|
|
_startDateController = TextEditingController(
|
|
text: widget.selectedItem?["start_date"] ?? "",
|
|
);
|
|
_endDateController = TextEditingController(
|
|
text: widget.selectedItem?['end_date'] ?? "",
|
|
);
|
|
|
|
_dateOfBirthController = TextEditingController(
|
|
text: widget.selectedItem?['nominee_dob'] ?? "",
|
|
);
|
|
_nomineerelationController = TextEditingController(
|
|
text: widget.selectedItem?['nominee_relationship'] ?? "",
|
|
);
|
|
_nomineeController = TextEditingController(
|
|
text: widget.selectedItem?['nominee_name'] ?? "",
|
|
);
|
|
|
|
// Set the selected value if available
|
|
if (widget.selectedItem != null &&
|
|
widget.selectedItem!["type_of_insurance"] != null) {
|
|
selectedInsuranceType =
|
|
widget.selectedItem!["type_of_insurance"].toString();
|
|
}
|
|
|
|
flightFirstTripDateNotifier = ValueNotifier<String?>(null);
|
|
flightLastTripDateNotifier = ValueNotifier<String?>(null);
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
final result = getFlightTripDateRange(widget.flightData);
|
|
flightFirstTripDateNotifier.value = result['firstTripDate'];
|
|
flightLastTripDateNotifier.value = result['lastTripDate'];
|
|
|
|
// ✅ Only set controller after value is updated
|
|
// final parsedDate =
|
|
// DateTime.tryParse(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 ?? '');
|
|
if (parsedEndDate != null) {
|
|
_endDateController.text = DateFormat(
|
|
'dd-MM-yyyy',
|
|
).format(parsedEndDate);
|
|
}
|
|
|
|
print("parsedDate $parsedDate");
|
|
print("parsedEndDate $parsedEndDate");
|
|
});
|
|
}
|
|
|
|
void loadInitialData() async {
|
|
String? layoutString = await getLayoutColor();
|
|
setState(() {
|
|
layoutColor =
|
|
layoutString != null
|
|
? Color(int.parse(layoutString))
|
|
: Colors.redAccent;
|
|
});
|
|
}
|
|
|
|
Map<String, String?> getFlightTripDateRange(
|
|
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};
|
|
}
|
|
|
|
allTrips.sort((a, b) {
|
|
final aDate = DateTime.tryParse(a['date'] ?? '') ?? DateTime(1900);
|
|
final bDate = DateTime.tryParse(b['date'] ?? '') ?? DateTime(1900);
|
|
return aDate.compareTo(bDate);
|
|
});
|
|
|
|
final firstTrip = allTrips.first;
|
|
final lastTrip = allTrips.last;
|
|
|
|
return {
|
|
'firstTripDate': firstTrip['date'],
|
|
'lastTripDate': lastTrip['date'],
|
|
};
|
|
}
|
|
|
|
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
|
node.addListener(() {
|
|
setState(() {
|
|
updateState(node.hasFocus);
|
|
});
|
|
});
|
|
}
|
|
|
|
bool isValidData(Map<String, dynamic> data) {
|
|
errorMessages.clear(); // Reset errors
|
|
|
|
// Required fields that must not be empty
|
|
List<String> requiredFields = [
|
|
"type_of_insurance",
|
|
"start_date",
|
|
"end_date",
|
|
"nominee_name",
|
|
"nominee_dob",
|
|
"nominee_relationship",
|
|
];
|
|
|
|
// Check validation for each field
|
|
for (String field in requiredFields) {
|
|
if (data[field] == null || data[field].toString().trim().isEmpty) {
|
|
errorMessages[field] = "Required";
|
|
}
|
|
}
|
|
final format = DateFormat("dd-MM-yyyy");
|
|
// Additional validation: checkout_date >= checkin_date
|
|
final checkIn = data["start_date"];
|
|
final checkOut = data["end_date"];
|
|
|
|
if (checkIn != null &&
|
|
checkOut != null &&
|
|
checkIn.toString().isNotEmpty &&
|
|
checkOut.toString().isNotEmpty) {
|
|
try {
|
|
final checkInDate = format.parse(checkIn);
|
|
final checkOutDate = format.parse(checkOut);
|
|
if (checkOutDate.isBefore(checkInDate)) {
|
|
errorMessages["end_date"] = "EndDate date cannot be before StartDate";
|
|
}
|
|
} catch (e) {
|
|
errorMessages["end_date"] = "Invalid date format";
|
|
}
|
|
}
|
|
|
|
return errorMessages.isEmpty; // Valid if there are no errors
|
|
}
|
|
|
|
void handleSave() {
|
|
print("Handle Save InsuranceData $InsuranceData");
|
|
|
|
Map<String, dynamic> data = InsuranceData;
|
|
|
|
if (!isValidData(data)) {
|
|
print("Validation Failed: Required fields are missing.");
|
|
setState(() {});
|
|
return; // Stop execution if validation fails
|
|
} else {
|
|
widget.onSaveInsurance(InsuranceData);
|
|
}
|
|
widget.onClose("Insurance", false);
|
|
// widget.onClose(false); // Close screen after saving
|
|
}
|
|
|
|
DateTime? _parseDate(String date) {
|
|
try {
|
|
return DateFormat("dd-MM-yyyy").parse(date); // Change format if needed
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
// Dispose all dynamically created FocusNodes
|
|
for (var node in focusNodes.values) {
|
|
node.dispose();
|
|
}
|
|
|
|
_tripTypeFocusNode.dispose();
|
|
_tripTypeController.dispose();
|
|
_startDateController.dispose();
|
|
_endDateController.dispose();
|
|
_insuranceCommentsController.dispose();
|
|
_nomineeController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
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.only(top: 30.0),
|
|
child: Center(
|
|
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
|
List<Widget> buildResponsiveRow(List<Widget> children) {
|
|
return [
|
|
isDesktop ? Row(children: children) : Column(children: children),
|
|
SizedBox(height: 10),
|
|
];
|
|
}
|
|
|
|
List<List<Widget>> rowBuilders = [
|
|
// _builClassType(isDesktop),
|
|
_buildSecondRow(isDesktop),
|
|
_buildSecondSubRow(isDesktop),
|
|
];
|
|
|
|
return [
|
|
// ...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
|
|
|
// Iterate over rowBuilders and wrap each in a responsive container
|
|
...rowBuilders.expand((row) => buildResponsiveRow(row)),
|
|
|
|
...buildResponsiveRow(_buildThirdRow(isDesktop)),
|
|
|
|
// Actions row remains a Row
|
|
];
|
|
}
|
|
|
|
// 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();
|
|
|
|
if (dropdownItems.isEmpty) {
|
|
dropdownItems.add(
|
|
DropdownMenuItem<String>(
|
|
value: null,
|
|
child: Text(
|
|
"No options available",
|
|
style: TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Default selected value
|
|
selectedInsuranceType ??=
|
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
|
|
|
return [
|
|
CustomTextFieldWrapper(
|
|
isFocused: _isHotelNameFocused,
|
|
isDesktop: isDesktop,
|
|
width:
|
|
isDesktop
|
|
? MediaQuery.of(context).size.width * 0.34
|
|
: MediaQuery.of(context).size.width * 0.66,
|
|
child: SizedBox(
|
|
height: 40,
|
|
child: DropdownButtonFormField<String>(
|
|
focusNode: _tripTypeFocusNode, // Assign the correct focus node
|
|
value: selectedInsuranceType,
|
|
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
decoration: InputDecoration(
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(
|
|
horizontal: 10,
|
|
), // Proper padding
|
|
),
|
|
onChanged:
|
|
purposeList.isNotEmpty
|
|
? (newValue) {
|
|
setState(() {
|
|
selectedInsuranceType = newValue;
|
|
if (selectedInsuranceType!.isNotEmpty) {
|
|
errorMessages.remove("type_of_insurance");
|
|
}
|
|
});
|
|
|
|
print(selectedInsuranceType);
|
|
}
|
|
: null,
|
|
|
|
items: dropdownItems,
|
|
),
|
|
),
|
|
),
|
|
];
|
|
}
|
|
|
|
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() ??
|
|
[];
|
|
|
|
// Find selected item object based on key
|
|
Map<String, dynamic>? selectedItem = purposeList.firstWhere(
|
|
(item) => item['dropdown_key'] == selectedInsuranceType,
|
|
orElse: () => {},
|
|
);
|
|
|
|
return [
|
|
CustomTextFieldWrapper(
|
|
isFocused: false,
|
|
isDesktop: isDesktop,
|
|
child: SizedBox(
|
|
height: 35,
|
|
width: double.infinity,
|
|
child: DropdownSearch<Map<String, dynamic>>(
|
|
popupProps: PopupProps.menu(
|
|
showSearchBox: false,
|
|
fit: FlexFit.loose,
|
|
constraints: BoxConstraints(maxHeight: 10),
|
|
menuProps: const MenuProps(backgroundColor: Colors.white),
|
|
itemBuilder: (context, item, isSelected) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 10,
|
|
vertical: 8,
|
|
),
|
|
child: Text(
|
|
item['dropdown_value'] ?? '',
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 12, // 👈 Smaller font size
|
|
color: Colors.black,
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
dropdownDecoratorProps: const DropDownDecoratorProps(
|
|
dropdownSearchDecoration: InputDecoration(
|
|
border: InputBorder.none, // No underline
|
|
|
|
contentPadding: EdgeInsets.symmetric(
|
|
horizontal: 10,
|
|
vertical: 5,
|
|
),
|
|
),
|
|
),
|
|
|
|
dropdownBuilder: (context, selectedItem) {
|
|
if (selectedItem == null || selectedItem.isEmpty) {
|
|
return Text(
|
|
"Select Insurance Type",
|
|
style: GoogleFonts.poppins(color: Colors.grey, fontSize: 13),
|
|
);
|
|
}
|
|
return Text(
|
|
selectedItem['dropdown_value'] ?? '',
|
|
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
);
|
|
},
|
|
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,
|
|
items: purposeList,
|
|
),
|
|
),
|
|
),
|
|
];
|
|
}
|
|
|
|
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();
|
|
|
|
if (dropdownItems.isEmpty) {
|
|
dropdownItems.add(
|
|
DropdownMenuItem<String>(
|
|
value: null,
|
|
child: Text(
|
|
"No options available",
|
|
style: TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Default selected value
|
|
selectedInsuranceType ??=
|
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
DateTime? _selectedCheckOutDate;
|
|
TimeOfDay? _selectedCheckOutTime;
|
|
|
|
Future<void> _selectCheckOutDate(BuildContext context) async {
|
|
DateTime now = DateTime.now();
|
|
DateTime today = DateTime(now.year, now.month, now.day);
|
|
|
|
// Parse date from notifier if available, else use today
|
|
DateTime initialDate;
|
|
if (flightFirstTripDateNotifier.value != null) {
|
|
try {
|
|
initialDate = DateTime.parse(flightFirstTripDateNotifier.value!);
|
|
} catch (e) {
|
|
initialDate = today;
|
|
}
|
|
} else {
|
|
initialDate = today;
|
|
}
|
|
|
|
// Use previously selected date if valid
|
|
if (_selectedCheckOutDate != null &&
|
|
_selectedCheckOutDate!.isAfter(today)) {
|
|
initialDate = _selectedCheckOutDate!;
|
|
}
|
|
|
|
final pickedDate = await showDatePicker(
|
|
context: context,
|
|
initialDate: initialDate,
|
|
firstDate: initialDate,
|
|
lastDate: DateTime(2100),
|
|
initialEntryMode: DatePickerEntryMode.calendarOnly,
|
|
);
|
|
|
|
// DateTime? pickedDate = await showDatePicker(
|
|
// context: context,
|
|
// initialDate: _selectedCheckOutDate != null &&
|
|
// _selectedCheckOutDate!.isAfter(today)
|
|
// ? _selectedCheckOutDate!
|
|
// : today,
|
|
// firstDate: today,
|
|
// lastDate: DateTime(2100),
|
|
// );
|
|
|
|
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
|
setState(() {
|
|
_selectedCheckOutDate = pickedDate;
|
|
_startDateController.text = DateFormat(
|
|
'dd-MM-yyyy',
|
|
).format(pickedDate);
|
|
});
|
|
}
|
|
}
|
|
|
|
Future<void> _selectEndCheckOutDate(BuildContext context) async {
|
|
DateTime now = DateTime.now();
|
|
DateTime today = DateTime(now.year, now.month, now.day);
|
|
|
|
// DateTime? checkInDate;
|
|
// try {
|
|
// checkInDate = DateTime.parse(_startDateController.text);
|
|
// } catch (e) {
|
|
// checkInDate = today;
|
|
// }
|
|
|
|
// // Ensure at least today is used
|
|
// DateTime firstDate = checkInDate.isAfter(today) ? checkInDate : today;
|
|
// DateTime initialDate = _selectedCheckOutDate != null &&
|
|
// _selectedCheckOutDate!.isAfter(firstDate)
|
|
// ? _selectedCheckOutDate!
|
|
// : firstDate;
|
|
|
|
// DateTime firstDate = checkInDate;
|
|
// DateTime initialDate =
|
|
// _selectedCheckOutDate != null &&
|
|
// _selectedCheckOutDate!.isAfter(firstDate)
|
|
// ? _selectedCheckOutDate!
|
|
// : firstDate;
|
|
|
|
DateTime? validFromDate;
|
|
|
|
try {
|
|
String fromDateText = _startDateController.text.trim();
|
|
print("Valid From Text: $fromDateText");
|
|
if (fromDateText.isNotEmpty) {
|
|
validFromDate = DateFormat('dd-MM-yyyy').parseStrict(fromDateText);
|
|
print("Parsed Valid From: $validFromDate");
|
|
}
|
|
} catch (e) {
|
|
print("Error parsing valid from date: $e");
|
|
}
|
|
|
|
// Use max(today, validFromDate) as firstDate
|
|
// DateTime firstDate = today;
|
|
DateTime firstDate = validFromDate ?? today;
|
|
if (validFromDate != null && validFromDate.isAfter(today)) {
|
|
firstDate = validFromDate;
|
|
}
|
|
final pickedDate = await showDatePicker(
|
|
context: context,
|
|
// initialDate: initialDate,
|
|
// firstDate: initialDate,
|
|
// firstDate: DateTime(1900),
|
|
initialDate: firstDate,
|
|
firstDate: firstDate,
|
|
lastDate: DateTime(2100),
|
|
initialEntryMode: DatePickerEntryMode.calendarOnly,
|
|
);
|
|
|
|
// final pickedDate = await showDatePicker(
|
|
// context: context,
|
|
// // initialDate: initialDate,
|
|
// initialDate: initialDate,
|
|
// firstDate: initialDate,
|
|
// lastDate: DateTime(2100),
|
|
// initialEntryMode: DatePickerEntryMode.calendarOnly,
|
|
// );
|
|
|
|
// DateTime? pickedDate = await showDatePicker(
|
|
// context: context,
|
|
// initialDate: _selectedCheckOutDate != null &&
|
|
// _selectedCheckOutDate!.isAfter(today)
|
|
// ? _selectedCheckOutDate!
|
|
// : today,
|
|
// firstDate: today,
|
|
// lastDate: DateTime(2100),
|
|
// );
|
|
|
|
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
|
setState(() {
|
|
_selectedCheckOutDate = pickedDate;
|
|
_endDateController.text = DateFormat('dd-MM-yyyy').format(pickedDate);
|
|
});
|
|
}
|
|
}
|
|
|
|
return [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
"Insurance Type *",
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
color: const Color(0xFF575A74),
|
|
),
|
|
),
|
|
const SizedBox(height: 5),
|
|
|
|
// ▼ Dropdown Wrapper ▼
|
|
// CustomTextFieldWrapper(
|
|
// isFocused: _isHotelNameFocused,
|
|
// isDesktop: isDesktop,
|
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null,
|
|
// child: SizedBox(
|
|
// height: 35,
|
|
// width: double.infinity,
|
|
// child: DropdownButtonFormField<String>(
|
|
// focusNode: _tripTypeFocusNode,
|
|
// value: selectedInsuranceType,
|
|
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
|
// decoration: const InputDecoration(
|
|
// border: InputBorder.none,
|
|
// 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,
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// ▼ Dropdown Wrapper ▼
|
|
CustomTextFieldWrapper(
|
|
// isFocused: _isHotelNameFocused,
|
|
isFocused: false,
|
|
padding: const EdgeInsets.symmetric(horizontal: 0),
|
|
isDesktop: isDesktop,
|
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null,
|
|
child: SizedBox(
|
|
height: 40,
|
|
width: double.infinity,
|
|
child: DropdownSearch<Map<String, dynamic>>(
|
|
items: purposeList.cast<Map<String, dynamic>>(),
|
|
selectedItem: purposeList.firstWhere(
|
|
(item) => item['dropdown_key'] == selectedInsuranceType,
|
|
orElse: () => {},
|
|
),
|
|
itemAsString: (item) => item['dropdown_value'] ?? '',
|
|
popupProps: PopupProps.menu(
|
|
showSearchBox: false,
|
|
fit: FlexFit.loose,
|
|
menuProps: const MenuProps(backgroundColor: Colors.white),
|
|
itemBuilder: (context, item, isSelected) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: 10,
|
|
vertical: 5,
|
|
),
|
|
child: Text(
|
|
item['dropdown_value'] ?? '',
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 12,
|
|
color: Colors.black,
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
|
dropdownSearchDecoration: InputDecoration(
|
|
// border: InputBorder.none, // No underline
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(
|
|
color:
|
|
(focusStates["type_of_insuranceFocusNode"] ?? false)
|
|
? layoutColor!
|
|
: Colors.white,
|
|
width: 0.5,
|
|
),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderSide: BorderSide(
|
|
color:
|
|
(focusStates["type_of_insuranceFocusNode"] ?? false)
|
|
? layoutColor!
|
|
: Colors.white,
|
|
// : const Color(0xFFD6D5E6),
|
|
width: 0.5,
|
|
// const Color(0xFFD6D5E6),
|
|
),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderSide: BorderSide(color: layoutColor!, width: 1),
|
|
),
|
|
contentPadding: const EdgeInsets.symmetric(
|
|
horizontal: 10,
|
|
vertical: 5,
|
|
),
|
|
),
|
|
// 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.black,
|
|
),
|
|
);
|
|
},
|
|
onChanged:
|
|
purposeList.isNotEmpty
|
|
? (Map<String, dynamic>? newValue) {
|
|
setState(() {
|
|
selectedInsuranceType = newValue?['dropdown_key'];
|
|
print(
|
|
"selected Insurance Type: ${selectedInsuranceType}",
|
|
);
|
|
});
|
|
}
|
|
: null,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
// 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),
|
|
// ),
|
|
// ),
|
|
// SizedBox(height: 5),
|
|
// CustomTextFieldWrapper(
|
|
// isFocused: _nomineeFocus,
|
|
// isDesktop: isDesktop,
|
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null,
|
|
// // width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : null,
|
|
// child: SizedBox(
|
|
// height: 40,
|
|
// child: TextField(
|
|
// focusNode: _nomineeFocusNode,
|
|
// controller: _nomineeController,
|
|
// style: TextStyle(fontSize: 12),
|
|
// decoration: InputDecoration(
|
|
// labelText: "Nominee",
|
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
// floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
// border: InputBorder.none,
|
|
// contentPadding: EdgeInsets.symmetric(vertical: 16),
|
|
// // contentPadding: EdgeInsets.symmetric(horizontal: 1,vertical: 1),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
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),
|
|
),
|
|
),
|
|
SizedBox(height: 5),
|
|
CustomTextFieldWrapper(
|
|
// isFocused: _startDateFocus,
|
|
isFocused: focusStates["start_dateFocused"] ?? false,
|
|
isDesktop: isDesktop,
|
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
|
|
child: SizedBox(
|
|
height: 40,
|
|
child: GestureDetector(
|
|
onTap: () async {
|
|
focusNodes["start_dateFocusNode"]?.requestFocus();
|
|
await _selectCheckOutDate(context);
|
|
if (_startDateController.text.isNotEmpty) {
|
|
setState(() {
|
|
errorMessages.remove(
|
|
"start_date",
|
|
); // Removes the key completely
|
|
});
|
|
}
|
|
},
|
|
child: AbsorbPointer(
|
|
child: TextField(
|
|
// focusNode: _startDateFocusNode,
|
|
focusNode: focusNodes["start_dateFocusNode"],
|
|
controller: _startDateController,
|
|
readOnly: true,
|
|
style: const TextStyle(fontSize: 12),
|
|
decoration: const InputDecoration(
|
|
labelText: "Select ",
|
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
|
suffixIcon: Icon(
|
|
Icons.calendar_today,
|
|
size: 16,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (errorMessages["start_date"] != null) ...[
|
|
SizedBox(height: 5), // Space before error message
|
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
|
],
|
|
],
|
|
),
|
|
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),
|
|
),
|
|
),
|
|
SizedBox(height: 5),
|
|
CustomTextFieldWrapper(
|
|
isFocused: focusStates["end_dateFocused"] ?? false,
|
|
isDesktop: isDesktop,
|
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
|
|
child: SizedBox(
|
|
height: 40,
|
|
child: GestureDetector(
|
|
onTap: () async {
|
|
focusNodes["end_dateFocusNode"]?.requestFocus();
|
|
await _selectEndCheckOutDate(context);
|
|
|
|
if (_endDateController.text.isNotEmpty) {
|
|
DateTime? startDate = _parseDate(_startDateController.text);
|
|
DateTime? endDate = _parseDate(_endDateController.text);
|
|
|
|
if (startDate != null &&
|
|
endDate != null &&
|
|
endDate.isBefore(startDate)) {
|
|
setState(() {
|
|
errorMessages["end_date"] =
|
|
"End date cannot be earlier than start date";
|
|
});
|
|
} else {
|
|
setState(() {
|
|
errorMessages.remove("end_date");
|
|
});
|
|
}
|
|
}
|
|
},
|
|
child: AbsorbPointer(
|
|
child: TextField(
|
|
// focusNode: _endDateFocusNode,
|
|
focusNode: focusNodes["end_dateFocusNode"],
|
|
controller: _endDateController,
|
|
readOnly: true,
|
|
style: const TextStyle(fontSize: 12),
|
|
decoration: const InputDecoration(
|
|
labelText: "Select ",
|
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
|
suffixIcon: Icon(
|
|
Icons.calendar_today,
|
|
size: 16,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (errorMessages["end_date"] != null) ...[
|
|
SizedBox(height: 5), // Space before error message
|
|
Text(
|
|
errorMessages["end_date"]!,
|
|
style: const TextStyle(color: Colors.red, fontSize: 12),
|
|
maxLines: 2, // Allow it to wrap onto two lines
|
|
overflow:
|
|
TextOverflow.ellipsis, // Add ellipsis if it still overflows
|
|
),
|
|
],
|
|
],
|
|
),
|
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
|
];
|
|
}
|
|
|
|
List<Widget> _buildSecondSubRow(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();
|
|
|
|
if (dropdownItems.isEmpty) {
|
|
dropdownItems.add(
|
|
DropdownMenuItem<String>(
|
|
value: null,
|
|
child: Text(
|
|
"No options available",
|
|
style: TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Default selected value
|
|
selectedInsuranceType ??=
|
|
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
DateTime? _selectedCheckDOBDate;
|
|
|
|
Future<void> _selectCheckDOBOutDate(BuildContext context) async {
|
|
DateTime now = DateTime.now();
|
|
DateTime today = DateTime(now.year, now.month, now.day);
|
|
|
|
// Parse date from notifier if available, else use today
|
|
DateTime initialDate;
|
|
|
|
initialDate = today;
|
|
|
|
final pickedDate = await showDatePicker(
|
|
context: context,
|
|
initialDate: initialDate,
|
|
firstDate: DateTime(1900),
|
|
lastDate: today,
|
|
initialEntryMode: DatePickerEntryMode.calendarOnly,
|
|
);
|
|
|
|
// DateTime? pickedDate = await showDatePicker(
|
|
// context: context,
|
|
// initialDate: _selectedCheckOutDate != null &&
|
|
// _selectedCheckOutDate!.isAfter(today)
|
|
// ? _selectedCheckOutDate!
|
|
// : today,
|
|
// firstDate: today,
|
|
// lastDate: DateTime(2100),
|
|
// );
|
|
|
|
if (pickedDate != null && pickedDate != _selectedCheckDOBDate) {
|
|
setState(() {
|
|
_selectedCheckDOBDate = pickedDate;
|
|
_dateOfBirthController.text = DateFormat(
|
|
'dd-MM-yyyy',
|
|
).format(pickedDate);
|
|
});
|
|
}
|
|
}
|
|
|
|
return [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
"Nominee*",
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
color: Color(0xFF575A74),
|
|
),
|
|
),
|
|
SizedBox(height: 5),
|
|
CustomTextFieldWrapper(
|
|
// isFocused: _nomineeFocus,
|
|
isFocused: focusStates["nominee_nameFocused"] ?? false,
|
|
isDesktop: isDesktop,
|
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null,
|
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null,
|
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : null,
|
|
child: SizedBox(
|
|
height: 40,
|
|
child: TextField(
|
|
focusNode: focusNodes["nominee_nameFocusNode"],
|
|
inputFormatters: [
|
|
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
|
|
],
|
|
// focusNode: _nomineeFocusNode,
|
|
controller: _nomineeController,
|
|
style: TextStyle(fontSize: 12),
|
|
decoration: InputDecoration(
|
|
labelText: "Nominee",
|
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
|
// contentPadding: EdgeInsets.symmetric(horizontal: 1,vertical: 1),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (errorMessages["nominee_name"] != null) ...[
|
|
SizedBox(height: 5), // Space before error message
|
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
|
],
|
|
],
|
|
),
|
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
"Date of Birth*",
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
color: Color(0xFF575A74),
|
|
),
|
|
),
|
|
SizedBox(height: 5),
|
|
CustomTextFieldWrapper(
|
|
isFocused: focusStates["nominee_dobFocused"] ?? false,
|
|
isDesktop: isDesktop,
|
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
|
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
|
|
child: SizedBox(
|
|
height: 40,
|
|
child: GestureDetector(
|
|
onTap: () async {
|
|
focusNodes["nominee_dobFocusNode"]?.requestFocus();
|
|
await _selectCheckDOBOutDate(context);
|
|
// await _selectDateOfBirth(context);
|
|
if (_dateOfBirthController.text.isNotEmpty) {
|
|
setState(() {
|
|
errorMessages.remove(
|
|
"nominee_dob",
|
|
); // Removes the key completely
|
|
});
|
|
}
|
|
},
|
|
child: AbsorbPointer(
|
|
child: TextField(
|
|
focusNode: focusNodes["nominee_dobFocusNode"],
|
|
controller: _dateOfBirthController,
|
|
readOnly: true,
|
|
style: const TextStyle(fontSize: 12),
|
|
decoration: const InputDecoration(
|
|
labelText: "Select ",
|
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
|
suffixIcon: Icon(
|
|
Icons.calendar_today,
|
|
size: 16,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (errorMessages["nominee_dob"] != null) ...[
|
|
SizedBox(height: 5), // Space before error message
|
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
|
],
|
|
],
|
|
),
|
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
"Relationship*",
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
color: Color(0xFF575A74),
|
|
),
|
|
),
|
|
SizedBox(height: 5),
|
|
|
|
//
|
|
CustomTextFieldWrapper(
|
|
isFocused: focusStates["nominee_relationshipFocused"] ?? false,
|
|
isDesktop: isDesktop,
|
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
|
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.31 : null,
|
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : null,
|
|
child: SizedBox(
|
|
height: 40,
|
|
child: TextField(
|
|
focusNode: focusNodes["nominee_relationshipFocusNode"],
|
|
controller: _nomineerelationController,
|
|
style: TextStyle(fontSize: 12),
|
|
inputFormatters: [
|
|
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
|
|
],
|
|
decoration: InputDecoration(
|
|
labelText: "Nominee Relationship",
|
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
|
// contentPadding: EdgeInsets.symmetric(horizontal: 1,vertical: 1),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
if (errorMessages["nominee_relationship"] != null) ...[
|
|
SizedBox(height: 5), // Space before error message
|
|
Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
|
|
],
|
|
],
|
|
),
|
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
|
];
|
|
}
|
|
|
|
List<Widget> _buildThirdRow(bool isDesktop) {
|
|
return [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
"Comments",
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
color: Color(0xFF575A74),
|
|
),
|
|
),
|
|
SizedBox(height: 5),
|
|
CustomTextFieldWrapper(
|
|
isFocused:
|
|
focusStates["commentsFocused"] ??
|
|
false, // Dropdown doesn't use focus
|
|
isDesktop: isDesktop,
|
|
width:
|
|
isDesktop
|
|
? MediaQuery.of(context).size.width * 0.31
|
|
: null, // MediaQuery.of(context).size.width * 0.66,
|
|
child: SizedBox(
|
|
height: 40,
|
|
child: TextField(
|
|
// focusNode: _commentsFocusNode,
|
|
focusNode: focusNodes["commentsFocusNode"],
|
|
controller: _insuranceCommentsController,
|
|
inputFormatters: [
|
|
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
|
|
],
|
|
style: TextStyle(fontSize: 12),
|
|
decoration: InputDecoration(
|
|
labelText: "Comments",
|
|
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (isDesktop) Spacer(),
|
|
SizedBox(height: 5),
|
|
Column(
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
children: _handleAction(isDesktop),
|
|
),
|
|
],
|
|
),
|
|
];
|
|
}
|
|
|
|
List<Widget> _handleAction(bool isDesktop) {
|
|
return [
|
|
// Close Button
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
widget.onClose("Insurance", false); // Close the dialog or screen
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.grey[400], // Light grey color
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
|
),
|
|
child: Text(
|
|
"Close",
|
|
style: GoogleFonts.poppins(color: Colors.white, fontSize: 12),
|
|
),
|
|
),
|
|
SizedBox(width: 10), // Space between buttons
|
|
// Save Changes Button
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
handleSave();
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
|
),
|
|
child: Text(
|
|
"Save Changes",
|
|
style: GoogleFonts.poppins(color: Colors.white, fontSize: 12),
|
|
),
|
|
),
|
|
];
|
|
}
|
|
}
|