This commit is contained in:
venbaittech 2025-06-12 18:20:54 +05:30
parent 4121213bff
commit 563f808dfc
5 changed files with 370 additions and 78 deletions

View File

@ -651,6 +651,16 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
),
columns: [
DataColumn(
label: Text(
'S.NO',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Trip ID',
@ -669,6 +679,16 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
),
),
DataColumn(
label: Text(
'Trip Type',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Emp Code',
@ -687,15 +707,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
),
),
DataColumn(
label: Text(
'Trip Type',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn(
label: Text(
'Created On',
@ -725,9 +737,21 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
],
rows:
paginatedPlans.map((plan) {
// paginatedPlans.map((plan)
paginatedPlans.asMap().entries.map((entry) {
int index = entry.key;
var plan = entry.value;
return DataRow(
cells: [
DataCell(
Text(
"${index + 1}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
),
),
DataCell(
Text(
plan.planId,
@ -748,6 +772,15 @@ class _ListAllPlansState extends State<ListAllPlans> {
overflow: TextOverflow.ellipsis,
),
),
DataCell(
Text(
plan.tripType,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
),
),
DataCell(
Text(
plan.employeeCode ?? " - ",
@ -768,15 +801,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
),
),
),
DataCell(
Text(
plan.tripType,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
),
),
DataCell(
Text(
_formatDate(plan.createdOn),

View File

@ -45,10 +45,13 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
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();
bool _isHotelNameFocused = false;
bool _startDateFocus = false;
@ -65,9 +68,12 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
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,
};
@ -125,6 +131,13 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
_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'] ?? "",
);
@ -147,15 +160,24 @@ 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 ?? '');
if (parsedDate != null) { _startDateController.text = DateFormat('dd-MM-yyyy').format(parsedDate); }
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); }
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");
});
}
@ -203,6 +225,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
"type_of_insurance",
"start_date",
"end_date",
"nominee_name",
"nominee_dob",
"nominee_relationship",
];
// Check validation for each field
@ -311,6 +336,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
List<List<Widget>> rowBuilders = [
// _builClassType(isDesktop),
_buildSecondRow(isDesktop),
_buildSecondSubRow(isDesktop),
];
return [
@ -752,7 +778,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedInsuranceType,
(item) => item['dropdown_key'] == selectedInsuranceType,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
@ -779,7 +805,10 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
dropdownDecoratorProps: const DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 10,vertical: 10,),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
),
),
dropdownBuilder: (context, selectedItem) {
@ -801,58 +830,59 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
);
},
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),
),
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,
@ -869,7 +899,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
CustomTextFieldWrapper(
isFocused: _startDateFocus,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
child: SizedBox(
height: 40,
child: GestureDetector(
@ -928,7 +958,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
CustomTextFieldWrapper(
isFocused: _endDateFocus,
isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null,
width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
child: SizedBox(
height: 40,
child: GestureDetector(
@ -982,7 +1012,8 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
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
overflow:
TextOverflow.ellipsis, // Add ellipsis if it still overflows
),
],
],
@ -991,6 +1022,229 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
];
}
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,
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: _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: _startDateFocus,
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 {
await _selectCheckDOBOutDate(context);
// await _selectDateOfBirth(context);
if (_dateOfBirthController.text.isNotEmpty) {
setState(() {
errorMessages.remove(
"nominee_dob",
); // Removes the key completely
});
}
},
child: AbsorbPointer(
child: TextField(
focusNode: _startDateFocusNode,
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: 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: _nomineeFocusNode,
controller: _nomineerelationController,
style: TextStyle(fontSize: 12),
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(

View File

@ -153,7 +153,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"address": controllers["address"]?.text,
"gender": selectedGender,
// "gender": personalDetailsKey.currentState?.selectedGender,
// "agent_supported_service_ids": selectedServiceIds,
"agent_supported_service_ids": selectedServiceIds,
"postal_code": controllers["postalCode"]?.text,
"country_code": selectedCountry,
"employee_code": controllers["employeeCode"]?.text,

View File

@ -451,7 +451,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
} else {
selectedServiceIds.add({"service_id": serviceId});
}
print("selectedServiceIdsUser --- $selectedServiceIds");
// Call the parent's callback
widget.onServiceIdsChanged!(selectedServiceIds);
});

View File

@ -3656,7 +3656,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
.map((e) => _buildVisaDataRow1(e, isDesktop)),
// _buildVisaDataRow1(isDesktop),
IconForVisa(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
" * I confirm my passport is valid for next 6 months",
style: GoogleFonts.poppins(fontSize: 10),
),
IconForVisa(),
],
),
],
);
}
@ -3677,6 +3686,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildVisaValidFrom(entry),
SizedBox(width: 15),
buildVisaValidUpTo(entry),
SizedBox(
height: 60,
child: Center(
@ -3713,6 +3723,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildVisaValidFrom(entry),
SizedBox(height: 8),
buildVisaValidUpTo(entry),
IconButton(
icon: Icon(
Icons.remove_circle_sharp,