merge with old code

This commit is contained in:
venba-Inspriron-3558 2025-06-12 19:06:47 +05:30
commit 03a5fbfaf1
19 changed files with 1214 additions and 603 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -651,6 +651,16 @@ class _ListAllPlansState extends State<ListAllPlans> {
), ),
), ),
columns: [ columns: [
DataColumn(
label: Text(
'S.NO',
style: GoogleFonts.poppins(
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Trip ID', '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( DataColumn(
label: Text( label: Text(
'Emp Code', '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( DataColumn(
label: Text( label: Text(
'Created On', 'Created On',
@ -725,9 +737,21 @@ class _ListAllPlansState extends State<ListAllPlans> {
), ),
], ],
rows: rows:
paginatedPlans.map((plan) { // paginatedPlans.map((plan)
paginatedPlans.asMap().entries.map((entry) {
int index = entry.key;
var plan = entry.value;
return DataRow( return DataRow(
cells: [ cells: [
DataCell(
Text(
"${index + 1}",
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
),
),
DataCell( DataCell(
Text( Text(
plan.planId, plan.planId,
@ -748,6 +772,15 @@ class _ListAllPlansState extends State<ListAllPlans> {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
DataCell(
Text(
plan.tripType,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
),
),
DataCell( DataCell(
Text( Text(
plan.employeeCode ?? " - ", plan.employeeCode ?? " - ",
@ -768,15 +801,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
), ),
), ),
), ),
DataCell(
Text(
plan.tripType,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
),
),
DataCell( DataCell(
Text( Text(
_formatDate(plan.createdOn), _formatDate(plan.createdOn),
@ -867,6 +892,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
); );
}, },
), ),
if (plan.statusValue ==
"Pending Approval" ||
plan.statusValue ==
"Partially Approved")
IconButton( IconButton(
icon: Image.asset( icon: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',

View File

@ -97,7 +97,7 @@ class _ApprovalListState extends State<ApprovalList> {
setState(() { setState(() {
futurePlans = fetchPlans(); futurePlans = fetchPlans();
}); });
print("Token availa");
// Wait for futurePlans to be fetched and update allPlans // Wait for futurePlans to be fetched and update allPlans
futurePlans.then((plans) { futurePlans.then((plans) {
setState(() { setState(() {
@ -186,7 +186,9 @@ class _ApprovalListState extends State<ApprovalList> {
if (response.statusCode == 200) { if (response.statusCode == 200) {
final data = json.decode(response.body); final data = json.decode(response.body);
print('plansJson1');
List<dynamic> plansJson = data['data']; List<dynamic> plansJson = data['data'];
print('plansJson $plansJson');
return plansJson.map((json) => Plan.fromJson(json)).toList(); return plansJson.map((json) => Plan.fromJson(json)).toList();
} else { } else {
throw Exception('Failed to load plans'); throw Exception('Failed to load plans');
@ -345,6 +347,8 @@ class _ApprovalListState extends State<ApprovalList> {
(plan.userName?.toLowerCase().contains(lowerQuery) ?? false) || (plan.userName?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.travellerName?.toLowerCase().contains(lowerQuery) ?? (plan.travellerName?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(plan.approverName?.toLowerCase().contains(lowerQuery) ??
false) ||
(plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) || (plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) || (plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) ||
(plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false); (plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false);
@ -672,7 +676,7 @@ class _ApprovalListState extends State<ApprovalList> {
), ),
DataColumn( DataColumn(
label: Text( label: Text(
'Emp Code', 'Traveller',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -681,7 +685,7 @@ class _ApprovalListState extends State<ApprovalList> {
), ),
DataColumn( DataColumn(
label: Text( label: Text(
'Traveller', 'Approver',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -751,19 +755,40 @@ class _ApprovalListState extends State<ApprovalList> {
), ),
), ),
DataCell( DataCell(
Text( Column(
plan.employeeCode ?? " - ", crossAxisAlignment:
style: TextStyle( CrossAxisAlignment.start,
fontSize: 13, mainAxisAlignment:
fontFamily: "Inter", MainAxisAlignment.center,
),
), children: [
), SizedBox(height: 1),
DataCell(
Text( Text(
plan.userName.isNotEmpty plan.userName.isNotEmpty
? plan.userName ? plan.userName
: plan.travellerName, : plan.travellerName,
style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
),
),
SizedBox(height: 3),
Expanded(
child: Text(
"(${plan.employeeCode})" ??
" - ",
style: GoogleFonts.poppins(
fontSize: 10,
// fontFamily: "Inter",
),
),
),
],
),
),
DataCell(
Text(
plan.approverName ?? " ",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
@ -875,6 +900,10 @@ class _ApprovalListState extends State<ApprovalList> {
); );
}, },
), ),
if (plan.statusValue ==
"Pending Approval" ||
plan.statusValue ==
"Partially Approved")
IconButton( IconButton(
icon: Image.asset( icon: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
@ -890,6 +919,9 @@ class _ApprovalListState extends State<ApprovalList> {
print( print(
"Approver Edit2 : ${plan.delegaterId}", "Approver Edit2 : ${plan.delegaterId}",
); );
print(
"Approver Edit3 : ${plan.approver_status}",
);
Navigator.pop( Navigator.pop(
context, context,
); );
@ -1130,6 +1162,10 @@ class _ApprovalListState extends State<ApprovalList> {
); );
}, },
), ),
if (plan.statusValue ==
"Pending Approval" ||
plan.statusValue ==
"Partially Approved")
IconButton( IconButton(
icon: Image.asset( icon: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
@ -1139,7 +1175,13 @@ class _ApprovalListState extends State<ApprovalList> {
tooltip: tooltip:
'Edit The Trip Details', 'Edit The Trip Details',
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(
context,
);
print(
"Approver Edit3 : ${plan.approver_status}",
);
ApiService.viewPlanForApprover( ApiService.viewPlanForApprover(
context, context,
plan.planId, plan.planId,

View File

@ -127,7 +127,6 @@ class ForexDataState extends State<ForexData> {
selectedCountryName = selectedCountryName =
data['country_name']; // For dropdown label or display data['country_name']; // For dropdown label or display
selectedCurrency = data['currency']; // Optional if used elsewhere selectedCurrency = data['currency']; // Optional if used elsewhere
controllers['currency']?.text = data['currency'] ?? ''; controllers['currency']?.text = data['currency'] ?? '';
controllers['cash']?.text = data['cash_percentage'] ?? ''; controllers['cash']?.text = data['cash_percentage'] ?? '';
controllers['card']?.text = data['card_percentage'] ?? ''; controllers['card']?.text = data['card_percentage'] ?? '';
@ -336,6 +335,16 @@ class ForexDataState extends State<ForexData> {
selectedCountry ??= null; selectedCountry ??= null;
void setCurrencyFromSelectedCountry(String selectedCountryCode) {
final matchedCountry = countryList.firstWhere(
(item) => item['country_code'] == selectedCountryCode,
orElse: () => {},
);
final currency = matchedCountry['currency'] ?? '';
controllers["currency"]?.text = currency;
}
return AlertDialog( return AlertDialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
contentPadding: const EdgeInsets.fromLTRB(34, 30, 34, 30), contentPadding: const EdgeInsets.fromLTRB(34, 30, 34, 30),
@ -426,6 +435,7 @@ class ForexDataState extends State<ForexData> {
.firstWhere((entry) => entry.value == newValue) .firstWhere((entry) => entry.value == newValue)
.key; .key;
selectedCountryName = newValue; selectedCountryName = newValue;
setCurrencyFromSelectedCountry(selectedCountry!);
}); });
}, },
), ),
@ -457,6 +467,7 @@ class ForexDataState extends State<ForexData> {
isFocused: false, isFocused: false,
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
color: Colors.transparent, color: Colors.transparent,
// width: isDesktop // width: isDesktop
// ? MediaQuery.of(context).size.width * 0.330 // ? MediaQuery.of(context).size.width * 0.330
// : MediaQuery.of(context).size.width * 0.66, // : MediaQuery.of(context).size.width * 0.66,
@ -464,9 +475,13 @@ class ForexDataState extends State<ForexData> {
height: 40, height: 40,
child: TextField( child: TextField(
controller: controllers["currency"], controller: controllers["currency"],
style: const TextStyle(fontSize: 12), style: GoogleFonts.poppins(
fontSize: 11,
color: Colors.black,
),
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Currency", labelText: "Currency",
enabled: false,
labelStyle: TextStyle(fontSize: 11, color: Colors.grey), labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,

View File

@ -356,6 +356,9 @@ class _ForexScreenState extends State<ForexScreen> {
print("card - $card"); print("card - $card");
print("cash - $cash"); print("cash - $cash");
_validateCardAmount(card);
_validateCashAmount(cash);
if (!isValidForexData(data)) { if (!isValidForexData(data)) {
// && errorMessages.isNotEmpty) { // && errorMessages.isNotEmpty) {
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
@ -411,7 +414,6 @@ class _ForexScreenState extends State<ForexScreen> {
textControllers["_forexStartDate"]?.addListener(_onFieldChanged); textControllers["_forexStartDate"]?.addListener(_onFieldChanged);
textControllers["_forexEndDate"]?.addListener(_onFieldChanged); textControllers["_forexEndDate"]?.addListener(_onFieldChanged);
flightFirstTripDateNotifier = ValueNotifier<String?>(null); flightFirstTripDateNotifier = ValueNotifier<String?>(null);
flightLastTripDateNotifier = ValueNotifier<String?>(null); flightLastTripDateNotifier = ValueNotifier<String?>(null);
@ -428,26 +430,62 @@ class _ForexScreenState extends State<ForexScreen> {
// Only set controller after value is updated // Only set controller after value is updated
// final parsedDate = // final parsedDate =
// DateTime.tryParse(flightFirstTripDateNotifier.value ?? ''); // DateTime.tryParse(flightFirstTripDateNotifier.value ?? '');
// -----------------------------------
// final parsedDate = DateFormat(
// "dd-MM-yyyy",
// ).parse(flightFirstTripDateNotifier.value ?? '');
// if (parsedDate != null) {
// textControllers["_forexStartDate"]?.text = DateFormat(
// 'dd-MM-yyyy',
// ).format(parsedDate);
// }
final flightDateStr = flightFirstTripDateNotifier.value;
if (flightDateStr != null && flightDateStr.trim().isNotEmpty) {
try {
final parsedDate = DateFormat( final parsedDate = DateFormat(
"dd-MM-yyyy", "dd-MM-yyyy",
).parse(flightFirstTripDateNotifier.value ?? ''); ).parse(flightDateStr.trim());
if (parsedDate != null) {
textControllers["_forexStartDate"]?.text = DateFormat( textControllers["_forexStartDate"]?.text = DateFormat(
'dd-MM-yyyy', 'dd-MM-yyyy',
).format(parsedDate); ).format(parsedDate);
} catch (e) {
print("Error parsing flightFirstTripDate: $e");
// Optionally show an error message to the user or log it
}
} else {
print("flightFirstTripDateNotifier is null or empty");
} }
final parsedEndDate = DateFormat( final flightDateEnd = flightLastTripDateNotifier.value;
if (flightDateEnd != null && flightDateEnd.trim().isNotEmpty) {
try {
final parsedDate = DateFormat(
"dd-MM-yyyy", "dd-MM-yyyy",
).parse(flightLastTripDateNotifier.value ?? ''); ).parse(flightDateEnd.trim());
if (parsedEndDate != null) {
textControllers["_forexEndDate"]?.text = DateFormat( textControllers["_forexEndDate"]?.text = DateFormat(
'dd-MM-yyyy', 'dd-MM-yyyy',
).format(parsedEndDate); ).format(parsedDate);
} catch (e) {
print("Error parsing flightEndTripDate: $e");
// Optionally show an error message to the user or log it
}
} else {
print("flightEndTripDateNotifier is null or empty");
} }
handleUpdatedField(); // final parsedEndDate = DateFormat(
// "dd-MM-yyyy",
// ).parse(flightLastTripDateNotifier.value ?? '');
// if (parsedEndDate != null) {
// textControllers["_forexEndDate"]?.text = DateFormat(
// 'dd-MM-yyyy',
// ).format(parsedEndDate);
// }
handleUpdatedField();
}); });
} }
@ -468,16 +506,22 @@ class _ForexScreenState extends State<ForexScreen> {
print("UPDATAED SELECTION"); print("UPDATAED SELECTION");
textControllers["_forexStartDate"] = initController("start_date"); textControllers["_forexStartDate"] = initController("start_date");
textControllers["_forexStartDate"]?.addListener(_onFieldChanged); // Reattach textControllers["_forexStartDate"]?.addListener(
_onFieldChanged,
); // Reattach
textControllers["_forexEndDate"] = initController("end_date"); textControllers["_forexEndDate"] = initController("end_date");
textControllers["_forexEndDate"]?.addListener(_onFieldChanged); // Reattach textControllers["_forexEndDate"]?.addListener(
_onFieldChanged,
); // Reattach
textControllers["_transport"] = initController("transport"); textControllers["_transport"] = initController("transport");
textControllers["_accomodation"] = initController("accommodation"); textControllers["_accomodation"] = initController("accommodation");
textControllers["_telephone"] = initController("telephone"); textControllers["_telephone"] = initController("telephone");
textControllers["_cardNumber"] = initController("card_number"); textControllers["_cardNumber"] = initController("card_number");
textControllers["_card"] = initController("deposit_on_card"); textControllers["_card"] = initController("deposit_on_card");
textControllers["_cash"] = initController("deposit_on_cash"); textControllers["_cash"] = initController("deposit_on_cash");
textControllers["_deliveryLocation"] = initController("delivery_location"); textControllers["_deliveryLocation"] = initController(
"delivery_location",
);
textControllers["_comments"] = initController("comments"); textControllers["_comments"] = initController("comments");
// Set dropdown values // Set dropdown values
@ -1162,7 +1206,8 @@ class _ForexScreenState extends State<ForexScreen> {
errorMessages["end_date"]!, errorMessages["end_date"]!,
style: const TextStyle(color: Colors.red, fontSize: 12), style: const TextStyle(color: Colors.red, fontSize: 12),
maxLines: 2, // Allow it to wrap onto two lines 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
), ),
], ],
], ],
@ -2129,7 +2174,7 @@ class _ForexScreenState extends State<ForexScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Delivery Location", "Delivery Location *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -2149,6 +2194,9 @@ class _ForexScreenState extends State<ForexScreen> {
child: TextField( child: TextField(
focusNode: focusNodes["_deliveryLocation"], focusNode: focusNodes["_deliveryLocation"],
controller: textControllers["_deliveryLocation"], controller: textControllers["_deliveryLocation"],
onChanged: (value) {
errorMessages.remove("delivery_location");
},
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Location", labelText: "Location",
@ -2194,10 +2242,10 @@ class _ForexScreenState extends State<ForexScreen> {
onChanged: (bool? value) { onChanged: (bool? value) {
setState(() { setState(() {
isChecked = value!; isChecked = value!;
if (isChecked) { // if (isChecked) {
textControllers["_cardNumber"] // textControllers["_cardNumber"]
?.clear(); // Clear the value when isChecked is true // ?.clear(); // Clear the value when isChecked is true
} // }
}); });
}, },
), ),

View File

@ -45,10 +45,13 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
late TextEditingController _tripTypeController = TextEditingController(); late TextEditingController _tripTypeController = TextEditingController();
late TextEditingController _startDateController = TextEditingController(); late TextEditingController _startDateController = TextEditingController();
late TextEditingController _dateOfBirthController = TextEditingController();
late TextEditingController _endDateController = TextEditingController(); late TextEditingController _endDateController = TextEditingController();
late TextEditingController _insuranceCommentsController = late TextEditingController _insuranceCommentsController =
TextEditingController(); TextEditingController();
late TextEditingController _nomineeController = TextEditingController(); late TextEditingController _nomineeController = TextEditingController();
late TextEditingController _nomineerelationController =
TextEditingController();
bool _isHotelNameFocused = false; bool _isHotelNameFocused = false;
bool _startDateFocus = false; bool _startDateFocus = false;
@ -65,9 +68,12 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
Map<String, dynamic> data = { Map<String, dynamic> data = {
"type_of_insurance": selectedInsuranceType, "type_of_insurance": selectedInsuranceType,
"start_date": _startDateController.text, "start_date": _startDateController.text,
"end_date": _endDateController.text, "end_date": _endDateController.text,
"comments": _insuranceCommentsController.text, "comments": _insuranceCommentsController.text,
"nominee_name": _nomineeController.text, "nominee_name": _nomineeController.text,
"nominee_dob": _dateOfBirthController.text,
"nominee_relationship": _nomineerelationController.text,
"created_by": widget.loginUser, "created_by": widget.loginUser,
"updated_by": widget.loginUser, "updated_by": widget.loginUser,
}; };
@ -125,6 +131,13 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
_endDateController = TextEditingController( _endDateController = TextEditingController(
text: widget.selectedItem?['end_date'] ?? "", text: widget.selectedItem?['end_date'] ?? "",
); );
_dateOfBirthController = TextEditingController(
text: widget.selectedItem?['nominee_dob'] ?? "",
);
_nomineerelationController = TextEditingController(
text: widget.selectedItem?['nominee_relationship'] ?? "",
);
_nomineeController = TextEditingController( _nomineeController = TextEditingController(
text: widget.selectedItem?['nominee_name'] ?? "", text: widget.selectedItem?['nominee_name'] ?? "",
); );
@ -147,15 +160,24 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
// Only set controller after value is updated // Only set controller after value is updated
// final parsedDate = // final parsedDate =
// DateTime.tryParse(flightFirstTripDateNotifier.value ?? ''); // DateTime.tryParse(flightFirstTripDateNotifier.value ?? '');
final parsedDate = DateFormat("dd-MM-yyyy").parse(flightFirstTripDateNotifier.value ?? ''); final parsedDate = DateFormat(
if (parsedDate != null) { _startDateController.text = DateFormat('dd-MM-yyyy').format(parsedDate); } "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(
if (parsedEndDate != null) { _endDateController.text = DateFormat('dd-MM-yyyy').format(parsedEndDate); } "dd-MM-yyyy",
).parse(flightLastTripDateNotifier.value ?? '');
if (parsedEndDate != null) {
_endDateController.text = DateFormat(
'dd-MM-yyyy',
).format(parsedEndDate);
}
print("parsedDate $parsedDate"); print("parsedDate $parsedDate");
print("parsedEndDate $parsedEndDate"); print("parsedEndDate $parsedEndDate");
}); });
} }
@ -203,6 +225,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
"type_of_insurance", "type_of_insurance",
"start_date", "start_date",
"end_date", "end_date",
"nominee_name",
"nominee_dob",
"nominee_relationship",
]; ];
// Check validation for each field // Check validation for each field
@ -311,6 +336,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
List<List<Widget>> rowBuilders = [ List<List<Widget>> rowBuilders = [
// _builClassType(isDesktop), // _builClassType(isDesktop),
_buildSecondRow(isDesktop), _buildSecondRow(isDesktop),
_buildSecondSubRow(isDesktop),
]; ];
return [ return [
@ -779,7 +805,10 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
dropdownDecoratorProps: const DropDownDecoratorProps( dropdownDecoratorProps: const DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration( dropdownSearchDecoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 10,vertical: 10,), contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
), ),
), ),
dropdownBuilder: (context, selectedItem) { dropdownBuilder: (context, selectedItem) {
@ -805,54 +834,55 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
? (Map<String, dynamic>? newValue) { ? (Map<String, dynamic>? newValue) {
setState(() { setState(() {
selectedInsuranceType = newValue?['dropdown_key']; selectedInsuranceType = newValue?['dropdown_key'];
print("selected Insurance Type: ${selectedInsuranceType}"); print(
"selected Insurance Type: ${selectedInsuranceType}",
);
}); });
} }
: null, : null,
), ),
), ),
), ),
], ],
), ),
if (isDesktop) Spacer() else SizedBox(height: 8), // if (isDesktop) Spacer() else SizedBox(height: 8),
Column( // Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
Text( // Text(
"Nominee", // "Nominee",
style: GoogleFonts.poppins( // style: GoogleFonts.poppins(
fontSize: 12, // fontSize: 12,
fontWeight: FontWeight.w600, // fontWeight: FontWeight.w600,
color: Color(0xFF575A74), // color: Color(0xFF575A74),
), // ),
), // ),
SizedBox(height: 5), // SizedBox(height: 5),
CustomTextFieldWrapper( // CustomTextFieldWrapper(
isFocused: _nomineeFocus, // isFocused: _nomineeFocus,
isDesktop: isDesktop, // isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, // width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null,
// width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : null, // // width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : null,
child: SizedBox( // child: SizedBox(
height: 40, // height: 40,
child: TextField( // child: TextField(
focusNode: _nomineeFocusNode, // focusNode: _nomineeFocusNode,
controller: _nomineeController, // controller: _nomineeController,
style: TextStyle(fontSize: 12), // style: TextStyle(fontSize: 12),
decoration: InputDecoration( // decoration: InputDecoration(
labelText: "Nominee", // labelText: "Nominee",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey), // labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, // floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, // border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), // contentPadding: EdgeInsets.symmetric(vertical: 16),
// contentPadding: EdgeInsets.symmetric(horizontal: 1,vertical: 1), // // contentPadding: EdgeInsets.symmetric(horizontal: 1,vertical: 1),
), // ),
), // ),
), // ),
), // ),
], // ],
), // ),
if (isDesktop) Spacer() else SizedBox(height: 8), if (isDesktop) Spacer() else SizedBox(height: 8),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -869,7 +899,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
CustomTextFieldWrapper( CustomTextFieldWrapper(
isFocused: _startDateFocus, isFocused: _startDateFocus,
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: GestureDetector( child: GestureDetector(
@ -928,7 +958,7 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
CustomTextFieldWrapper( CustomTextFieldWrapper(
isFocused: _endDateFocus, isFocused: _endDateFocus,
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.16 : null,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: GestureDetector( child: GestureDetector(
@ -982,7 +1012,8 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
errorMessages["end_date"]!, errorMessages["end_date"]!,
style: const TextStyle(color: Colors.red, fontSize: 12), style: const TextStyle(color: Colors.red, fontSize: 12),
maxLines: 2, // Allow it to wrap onto two lines 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) { List<Widget> _buildThirdRow(bool isDesktop) {
return [ return [
Column( Column(

View File

@ -51,10 +51,15 @@ class _FlightListWidgetState extends State<FlightListWidget> {
Map<String, String> tempCountryMap = {}; Map<String, String> tempCountryMap = {};
for (var country in result) { for (var country in result) {
String city = country['City'] ?? ''; // String city = country['City'] ?? '';
String airport = country['Airport'] ?? ''; // String airport = country['Airport'] ?? '';
String displayName = '${country['City']} - ${country['Airport']}'; // String displayName = '${country['City']} - ${country['Airport']}';
// String displayName = '${country['City']} | ${country['Airport']}'; // // String displayName = '${country['City']} | ${country['Airport']}';
final code = country['Code'] ?? '';
final city = country['City'] ?? '';
final airport = country['Airport'] ?? '';
final displayName = '$city ($code)\n$airport';
tempCountryMap[country['Code']] = displayName; tempCountryMap[country['Code']] = displayName;
} }
@ -346,7 +351,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
), ),
Expanded( Expanded(
flex: 4, flex: 5,
child: Text( child: Text(
"Sector", "Sector",
style: GoogleFonts.poppins(fontSize: 11), style: GoogleFonts.poppins(fontSize: 11),
@ -374,13 +379,38 @@ class _FlightListWidgetState extends State<FlightListWidget> {
if (isDesktop) if (isDesktop)
if (item["trips"] != null && item["trips"].isNotEmpty) if (item["trips"] != null && item["trips"].isNotEmpty)
...item["trips"].map<Widget>((trip) { ...item["trips"].map<Widget>((trip) {
print("werewrewrTrip - $trip");
String fromPlaceCountry = String fromPlaceCountry =
countryMap[trip["from_place"]?.toString()] ?? countryMap[trip["from_place"]?.toString()] ??
"Unknown Country"; "Unknown Country";
final parts = fromPlaceCountry.split('\n');
final cityAndCode = parts[0];
final fromairport = parts.length > 1 ? parts[1] : '';
// Extract city and code from "City (CODE)"
final cityMatch = RegExp(
r'^(.*)\s+\(([^)]+)\)$',
).firstMatch(cityAndCode);
final fromcity = cityMatch?.group(1) ?? '';
final fromcode = cityMatch?.group(2) ?? '';
String toPlaceCountry = String toPlaceCountry =
countryMap[trip["to_place"]?.toString()] ?? countryMap[trip["to_place"]?.toString()] ??
"Unknown Country"; "Unknown Country";
final toparts = toPlaceCountry.split('\n');
final tocityAndCode = toparts[0];
final toairport = toparts.length > 1 ? toparts[1] : '';
// Extract city and code from "City (CODE)"
final tocityMatch = RegExp(
r'^(.*)\s+\(([^)]+)\)$',
).firstMatch(tocityAndCode);
final tocity = tocityMatch?.group(1) ?? '';
final tocode = tocityMatch?.group(2) ?? '';
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0), padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row( child: Row(
@ -398,36 +428,74 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
Expanded( Expanded(
flex: 4, flex: 4,
child: Column( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"$fromPlaceCountry", "$fromcity ($fromcode)",
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
), ),
), ),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Image.asset(
'assets/images/IconsImg/alternate.png',
width: 20,
height: 20,
),
),
Text( Text(
"$toPlaceCountry", "$fromairport",
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 10,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w400,
), ),
), ),
], ],
), ),
), ),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: Image.asset(
'assets/images/IconsImg/Frame.png',
width: 20,
height: 20,
),
),
),
Expanded(
flex: 1,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"$tocity ($tocode)",
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w700,
),
),
Text(
"$toairport",
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w400,
),
),
],
),
),
],
),
),
Spacer(),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
@ -478,6 +546,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
"Sector", "Sector",
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}", "${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}",
), ),
_buildKeyValueRow( _buildKeyValueRow(
"Date", "Date",
formatDate(trip["date"] ?? ""), formatDate(trip["date"] ?? ""),

View File

@ -54,7 +54,8 @@ class _TrainListWidgetState extends State<TrainListWidget> {
return AlertDialog( return AlertDialog(
title: const Text('Select Trip Type'), title: const Text('Select Trip Type'),
content: const Text( content: const Text(
'Please select a trip type before adding a Train.'), 'Please select a trip type before adding a Train.',
),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
@ -109,16 +110,19 @@ class _TrainListWidgetState extends State<TrainListWidget> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
MouseRegion( MouseRegion(
cursor: widget.isViewMode cursor:
widget.isViewMode
? SystemMouseCursors.forbidden ? SystemMouseCursors.forbidden
: SystemMouseCursors.click, : SystemMouseCursors.click,
child: MouseRegion( child: MouseRegion(
cursor: widget.isViewMode cursor:
widget.isViewMode
? SystemMouseCursors.forbidden ? SystemMouseCursors.forbidden
: SystemMouseCursors.click, : SystemMouseCursors.click,
child: GestureDetector( child: GestureDetector(
onTap: widget.isViewMode onTap:
widget.isViewMode
? null ? null
: () { : () {
print("New data"); print("New data");
@ -137,7 +141,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
Icons.add_circle_sharp, Icons.add_circle_sharp,
size: 30, size: 30,
color: Color(0xFF114D8B), color: Color(0xFF114D8B),
) ),
], ],
), ),
), ),
@ -193,9 +197,9 @@ class _TrainListWidgetState extends State<TrainListWidget> {
], ],
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop) // Scroll behavior based on device
_buildData(context, isDesktop),
], ],
), ),
), ),
@ -268,8 +272,11 @@ class _TrainListWidgetState extends State<TrainListWidget> {
if (hour == 24 && minute == 0) { if (hour == 24 && minute == 0) {
// 24:00 is treated as 00:00 on the next day // 24:00 is treated as 00:00 on the next day
dateTime = DateTime(now.year, now.month, now.day) dateTime = DateTime(
.add(const Duration(days: 1)); now.year,
now.month,
now.day,
).add(const Duration(days: 1));
} else { } else {
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
throw FormatException("Invalid hour or minute"); throw FormatException("Invalid hour or minute");
@ -356,9 +363,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
), ),
], ],
), ),
Divider( Divider(color: Colors.blueGrey.shade50),
color: Colors.blueGrey.shade50,
),
SizedBox(height: 4), SizedBox(height: 4),
isDesktop isDesktop
? Row( ? Row(
@ -367,34 +372,30 @@ class _TrainListWidgetState extends State<TrainListWidget> {
flex: 2, flex: 2,
child: Text( child: Text(
" Class", " Class",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
Expanded( Expanded(
flex: 2, flex: 4,
child: Text( child: Text(
" Planned Trips", " Planned Trips",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
" Date", " Date",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
" Comments", " Comments",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
], ],
) )
: SizedBox.shrink(), : SizedBox.shrink(),
@ -410,20 +411,103 @@ class _TrainListWidgetState extends State<TrainListWidget> {
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
)), ),
),
SizedBox(width: 10), SizedBox(width: 10),
Expanded( Expanded(
flex: 2, flex: 3,
child: Text(
"$fromPlaceCountry - $toPlaceCountry", // child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Expanded(
// flex: 1,
// child: Text(
// "$fromPlaceCountry",
// // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w700,
// ),
// ),
// ),
// Expanded(
// flex: 1,
// child: Padding(
// padding: const EdgeInsets.only(left: 10),
// child: Image.asset(
// 'assets/images/IconsImg/Frame.png',
// width: 20,
// height: 20,
// ),
// ),
// ),
// Expanded(
// flex: 1,
// child: Text(
// "$toPlaceCountry",
// // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w700,
// ),
// ),
// ),
// ],
// ),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"$fromPlaceCountry ",
// "${item["from_station"]!} - ${(item["to_station"])}", // "${item["from_station"]!} - ${(item["to_station"])}",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
)), ),
SizedBox(width: 10), ],
),
),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: Image.asset(
'assets/images/IconsImg/Frame.png',
width: 20,
height: 20,
),
),
),
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"$toPlaceCountry",
// "$fromPlaceCountry - $toPlaceCountry",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
),
Spacer(),
// SizedBox(width: 10),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
@ -438,7 +522,9 @@ class _TrainListWidgetState extends State<TrainListWidget> {
Expanded( Expanded(
flex: 2, flex: 2,
child: _buildComments( child: _buildComments(
"Comments:", item["comments"] ?? "N/A"), "Comments:",
item["comments"] ?? "N/A",
),
), ),
], ],
) )
@ -447,8 +533,8 @@ class _TrainListWidgetState extends State<TrainListWidget> {
children: [ children: [
_buildRow( _buildRow(
"Class:", "Class:",
getRequestForTrainClass( getRequestForTrainClass(item["class"]!.toString()),
item["class"]!.toString())), ),
_buildRow("From:", item["from_station"]!), _buildRow("From:", item["from_station"]!),
_buildRow("To:", item["to_station"]!), _buildRow("To:", item["to_station"]!),
_buildDateTimeRow( _buildDateTimeRow(
@ -458,7 +544,7 @@ class _TrainListWidgetState extends State<TrainListWidget> {
), ),
_buildRow("Comments:", item["comments"] ?? "N/A"), _buildRow("Comments:", item["comments"] ?? "N/A"),
], ],
) ),
], ],
), ),
), ),
@ -487,30 +573,36 @@ class _TrainListWidgetState extends State<TrainListWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: exceedsLimit child:
exceedsLimit
? Tooltip( ? Tooltip(
message: wrapText(value, 50), message: wrapText(value, 50),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
textStyle: textStyle: TextStyle(
TextStyle(color: Colors.black), // Tooltip text color color: Colors.black,
), // Tooltip text color
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
preferBelow: false, preferBelow: false,
child: Text(value.substring(0, limit) + "...", child: Text(
value.substring(0, limit) + "...",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontFamily: "Archivo"), fontFamily: "Archivo",
overflow: TextOverflow.ellipsis), ),
overflow: TextOverflow.ellipsis,
),
) )
: Text( : Text(
value, value,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontFamily: "Archivo"), fontFamily: "Archivo",
),
), ),
), ),
], ],
@ -538,36 +630,30 @@ class _TrainListWidgetState extends State<TrainListWidget> {
children: [ children: [
Text( Text(
title, title,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600),
fontSize: 12,
fontWeight: FontWeight.w600,
),
), ),
SizedBox(width: 8), SizedBox(width: 8),
Expanded( Expanded(
child: exceedsLimit child:
exceedsLimit
? Tooltip( ? Tooltip(
message: wrapText(value, 50), message: wrapText(value, 50),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade200, // Black background color: Colors.grey.shade200, // Black background
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
textStyle: textStyle: TextStyle(
TextStyle(color: Colors.black), // Tooltip text color color: Colors.black,
), // Tooltip text color
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
preferBelow: false, preferBelow: false,
child: Text(value.substring(0, limit) + "...", child: Text(
style: GoogleFonts.poppins( value.substring(0, limit) + "...",
fontSize: 12, style: GoogleFonts.poppins(fontSize: 12),
overflow: TextOverflow.ellipsis,
), ),
overflow: TextOverflow.ellipsis),
) )
: Text( : Text(value, style: GoogleFonts.poppins(fontSize: 12)),
value,
style: GoogleFonts.poppins(
fontSize: 12,
),
),
), ),
], ],
); );
@ -579,18 +665,10 @@ class _TrainListWidgetState extends State<TrainListWidget> {
children: [ children: [
Text( Text(
title, title,
style: TextStyle( style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12),
fontWeight: FontWeight.w600,
fontSize: 12,
),
), ),
SizedBox(width: 8), SizedBox(width: 8),
Expanded( Expanded(child: Text("$date, $time", style: TextStyle(fontSize: 12))),
child: Text(
"$date, $time",
style: TextStyle(fontSize: 12),
),
),
], ],
); );
} }

View File

@ -282,6 +282,8 @@ class _CreatePlansState extends State<CreatePlan> {
context.go('/listAllPlan'); context.go('/listAllPlan');
} else if (currentUri == "/createPlan") { } else if (currentUri == "/createPlan") {
context.go('/listPlan'); context.go('/listPlan');
} else if (currentUri == "/approver/plans") {
context.go('/approvallist');
} else { } else {
isApprover ? context.go('/approvallist') : context.go('/listPlan'); isApprover ? context.go('/approvallist') : context.go('/listPlan');
} }
@ -1173,17 +1175,18 @@ class CreateNewPlansState extends State<CreateNewPlan> {
print("ViewAAA - $planData"); print("ViewAAA - $planData");
print("Call viewPlanForApprover"); print("Call viewPlanForApprover");
ApiService.viewPlanForApprover( // ApiService.viewPlanForApprover(
context, // context,
data['plan_id'], // data['plan_id'],
data['approverId'], // data['approverId'],
data['delegaterId'], // data['delegaterId'],
data['approver_status'], // data['approver_status'],
//
isViewMode: false, // isViewMode: false,
isApprover: true, // isApprover: true,
); // );
// Close loading dialog (ONLY if still mounted)
if (mounted) Navigator.of(context, rootNavigator: true).pop();
context.go('/approvallist'); context.go('/approvallist');
} else { } else {
print("$methodName failed. Status: ${response.statusCode}"); print("$methodName failed. Status: ${response.statusCode}");
@ -3172,6 +3175,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
statusValue = "Approved"; statusValue = "Approved";
}); });
callApproveAPI(selectedPlanId!, planData['user_id']); callApproveAPI(selectedPlanId!, planData['user_id']);
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const SavingLoader(),
);
} else if (result is String) { } else if (result is String) {
// User rejected with remarks // User rejected with remarks
_remarksController.text = result; _remarksController.text = result;

View File

@ -153,7 +153,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"address": controllers["address"]?.text, "address": controllers["address"]?.text,
"gender": selectedGender, "gender": selectedGender,
// "gender": personalDetailsKey.currentState?.selectedGender, // "gender": personalDetailsKey.currentState?.selectedGender,
// "agent_supported_service_ids": selectedServiceIds,
"agent_supported_service_ids": selectedServiceIds, "agent_supported_service_ids": selectedServiceIds,
"postal_code": controllers["postalCode"]?.text, "postal_code": controllers["postalCode"]?.text,
"country_code": selectedCountry, "country_code": selectedCountry,
"employee_code": controllers["employeeCode"]?.text, "employee_code": controllers["employeeCode"]?.text,
@ -720,7 +722,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
if (start_Date != null && if (start_Date != null &&
end_Date != null && end_Date != null &&
end_Date.isBefore(start_Date)) { end_Date.isBefore(start_Date)) {
print("End date cannot be earlier than start date"); print("Invalid Date Range");
return; return;
} }
} catch (e) { } catch (e) {
@ -1420,6 +1422,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
disabledBackgroundColor: disabledBackgroundColor:
layoutColor, // Ensure color remains when disabled layoutColor, // Ensure color remains when disabled
disabledForegroundColor: Colors.white, disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: BorderSide(color: layoutColor, width: 2), side: BorderSide(color: layoutColor, width: 2),
@ -1482,9 +1485,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
disabledForegroundColor: Colors.white, disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: BorderSide(color: Colors.white, width: 2), side: BorderSide(color: layoutColor, width: 2),
), ),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 18),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
), ),
onPressed: handleBack, onPressed: handleBack,
// onPressed: // onPressed:

View File

@ -457,7 +457,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["employee_code"]!, widget.errorMessages["employee_code"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],

View File

@ -314,8 +314,8 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 20), SizedBox(height: 20),
_buildPassportDataRow1(widget.isDesktop), // _buildPassportDataRow1(widget.isDesktop),
SizedBox(height: 10), // SizedBox(height: 10),
_buildFirstRow(widget.isDesktop), _buildFirstRow(widget.isDesktop),
SizedBox(height: 10), SizedBox(height: 10),
_buildSecondRow(widget.isDesktop), _buildSecondRow(widget.isDesktop),
@ -451,7 +451,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
} else { } else {
selectedServiceIds.add({"service_id": serviceId}); selectedServiceIds.add({"service_id": serviceId});
} }
print("selectedServiceIdsUser --- $selectedServiceIds");
// Call the parent's callback // Call the parent's callback
widget.onServiceIdsChanged!(selectedServiceIds); widget.onServiceIdsChanged!(selectedServiceIds);
}); });
@ -802,7 +802,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["first_name"]!, widget.errorMessages["first_name"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -848,7 +848,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["last_name"]!, widget.errorMessages["last_name"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -1168,7 +1168,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["email"]!, widget.errorMessages["email"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -1229,7 +1229,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["mobile_no"]!, widget.errorMessages["mobile_no"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -1281,7 +1281,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["alternate_mobile_no"]!, widget.errorMessages["alternate_mobile_no"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -1612,7 +1612,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["role_id"]!, widget.errorMessages["role_id"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -1703,7 +1703,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["password"]!, widget.errorMessages["password"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],

View File

@ -195,7 +195,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
end_Date != null && end_Date != null &&
end_Date.isBefore(start_Date)) { end_Date.isBefore(start_Date)) {
setState(() { setState(() {
errorMessages["date_of_expiry"] = "End date cannot be earlier"; errorMessages["date_of_expiry"] = "Invalid Date Range";
}); });
print("End date cannot be earlier than start date"); print("End date cannot be earlier than start date");
} }
@ -227,28 +227,44 @@ class TravellerDetailsState extends State<TravellerDetails> {
// } // }
// } // }
// valid_from: 20-06-2025, valid_upto: 19-06-2025 // Visa entries: Validate valid_from < valid_upto for each entry
// DateTime? valid_from = data?['valid_from']; for (var entry in visaEntries) {
// DateTime? valid_upto = data?['valid_upto']; final localId = entry["local_id"];
// final fromText = entry["controller_valid_from"]?.text.trim();
// if (valid_from != null && final toText = entry["controller_valid_upto"]?.text.trim();
// valid_upto != null &&
// valid_from.toString().isNotEmpty && if (fromText != null &&
// valid_upto.toString().isNotEmpty) { toText != null &&
// try { fromText.isNotEmpty &&
// final format = DateFormat("dd-MM-yyyy"); toText.isNotEmpty) {
// final checkValidFrom = format.parse("$valid_from"); try {
// final checkValidUpto = format.parse("$valid_upto"); final fromDate = format.parseStrict(fromText);
// final toDate = format.parseStrict(toText);
// if (checkValidUpto.isBefore(checkValidFrom)) {
// // return "valid upto cannot be earlier than valid from"; if (toDate.isBefore(fromDate)) {
// } print("VisaErroer1");
// } catch (e) { errorMessages["valid_upto${entry['local_id']}"] =
// // return "valid upto cannot be earlier than valid from"; "Invalid date range";
// // errorMessages["valid_upto_$localId"] =
// // errorMessages["end_date"] = "Invalid date format"; // "Valid Upto can't be before Valid From";
// } } else {
// } print("VisaErroer2");
// errorMessages.remove("valid_upto$localId");
errorMessages.remove("valid_upto${entry['local_id']}");
}
} catch (e) {
print("VisaErroer3");
errorMessages["valid_upto${entry['local_id']}"] =
"Invalid date format";
}
}
}
if (errorMessages.isNotEmpty) {
print("Validation failed with errors: $errorMessages");
setState(() {}); // Refresh UI to show errors
return false;
}
print("travel validation end"); print("travel validation end");
return true; return true;
} }
@ -1379,7 +1395,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
errorMessages["passport_number"]!, errorMessages["passport_number"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -1458,8 +1474,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
// Revalidate expiry // Revalidate expiry
if (_selectedDateOfExpiry != null && if (_selectedDateOfExpiry != null &&
_selectedDateOfExpiry!.isBefore(_selectedDateOfIssue!)) { _selectedDateOfExpiry!.isBefore(_selectedDateOfIssue!)) {
errorMessages["date_of_expiry"] = errorMessages["date_of_expiry"] = "Invalid Date Range";
"Expiry date cannot be earlier than Issue date";
} else { } else {
errorMessages.remove("date_of_expiry"); errorMessages.remove("date_of_expiry");
} }
@ -1585,8 +1600,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
if (_selectedDateOfIssue != null && if (_selectedDateOfIssue != null &&
_selectedDateOfExpiry!.isBefore(_selectedDateOfIssue!)) { _selectedDateOfExpiry!.isBefore(_selectedDateOfIssue!)) {
errorMessages["date_of_expiry"] = errorMessages["date_of_expiry"] = "Invalid Date Range";
"Expiry date cannot be earlier than Issue date";
} else { } else {
errorMessages.remove("date_of_expiry"); errorMessages.remove("date_of_expiry");
} }
@ -1668,7 +1682,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
errorMessages["date_of_expiry"]!, errorMessages["date_of_expiry"]!,
style: const TextStyle(color: Colors.red, fontSize: 10), style: GoogleFonts.poppins(color: Colors.red, fontSize: 10),
maxLines: 2, // Allow it to wrap onto two lines maxLines: 2, // Allow it to wrap onto two lines
overflow: overflow:
TextOverflow.ellipsis, // Add ellipsis if it still overflows TextOverflow.ellipsis, // Add ellipsis if it still overflows
@ -2202,7 +2216,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
vertical: 8, vertical: 8,
), ),
child: Text( child: Text(
item['dropdown_value'] ?? '', item['dropdown_value'] ?? 'Select',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black, color: Colors.black,
@ -2214,7 +2228,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
dropdownDecoratorProps: const DropDownDecoratorProps( dropdownDecoratorProps: const DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration( dropdownSearchDecoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
hintText: "Select Seat", hintText: "Select",
contentPadding: EdgeInsets.symmetric( contentPadding: EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
vertical: 5, vertical: 5,
@ -2227,7 +2241,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
dropdownBuilder: (context, selectedItem) { dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) { if (selectedItem == null || selectedItem.isEmpty) {
return Text( return Text(
"Select Seat", // fallback text "Select ", // fallback text
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.grey, color: Colors.grey,
@ -2235,7 +2249,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
); );
} }
return Text( return Text(
selectedItem['dropdown_value'] ?? "Select Seat", selectedItem['dropdown_value'] ?? "Select ",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
); );
}, },
@ -2615,7 +2629,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
vertical: 8, vertical: 8,
), ),
child: Text( child: Text(
item['dropdown_value'] ?? '', item['dropdown_value'] ?? 'Select Seat',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Colors.black, color: Colors.black,
@ -2905,7 +2919,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
errorMessages["forex_pre_paid_card_number"]!, errorMessages["forex_pre_paid_card_number"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: GoogleFonts.poppins(color: Colors.red, fontSize: 12),
), ),
], ],
], ],
@ -3642,8 +3656,17 @@ class TravellerDetailsState extends State<TravellerDetails> {
.map((e) => _buildVisaDataRow1(e, isDesktop)), .map((e) => _buildVisaDataRow1(e, isDesktop)),
// _buildVisaDataRow1(isDesktop), // _buildVisaDataRow1(isDesktop),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
" * I confirm my passport is valid for next 6 months",
style: GoogleFonts.poppins(fontSize: 10),
),
IconForVisa(), IconForVisa(),
], ],
),
],
); );
} }
@ -3663,6 +3686,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildVisaValidFrom(entry), buildVisaValidFrom(entry),
SizedBox(width: 15), SizedBox(width: 15),
buildVisaValidUpTo(entry), buildVisaValidUpTo(entry),
SizedBox( SizedBox(
height: 60, height: 60,
child: Center( child: Center(
@ -3699,6 +3723,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildVisaValidFrom(entry), buildVisaValidFrom(entry),
SizedBox(height: 8), SizedBox(height: 8),
buildVisaValidUpTo(entry), buildVisaValidUpTo(entry),
IconButton( IconButton(
icon: Icon( icon: Icon(
Icons.remove_circle_sharp, Icons.remove_circle_sharp,
@ -4165,6 +4190,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
initialEntryMode: DatePickerEntryMode.calendarOnly, initialEntryMode: DatePickerEntryMode.calendarOnly,
); );
print("CheckOut - $_selectedCheckOutDate");
print("CheckIn - $_selectedCheckInDate");
if (pickedDate != null && pickedDate != _selectedCheckOutDate) { if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
setState(() { setState(() {
_selectedCheckInDate = pickedDate; _selectedCheckInDate = pickedDate;
@ -4175,10 +4203,14 @@ class TravellerDetailsState extends State<TravellerDetails> {
// Revalidate expiry // Revalidate expiry
if (_selectedCheckOutDate != null && if (_selectedCheckOutDate != null &&
_selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) { _selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) {
errorMessages["valid_upto"] = print("Entry - $entry");
"valid upto cannot be earlier than valid from"; print("errorMessages - $errorMessages");
errorMessages["valid_upto${entry['local_id']}"] =
"Invalid Date Range";
// errorMessages["valid_upto"] = "Invalid Date Range";
} else { } else {
errorMessages.remove("valid_upto"); errorMessages.remove("valid_upto${entry['local_id']}");
// errorMessages.remove("valid_upto");
} }
}); });
} }
@ -4293,10 +4325,10 @@ class TravellerDetailsState extends State<TravellerDetails> {
if (_selectedCheckInDate != null && if (_selectedCheckInDate != null &&
_selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) { _selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) {
errorMessages["valid_upto"] = errorMessages["valid_upto${entry['local_id']}"] =
"valid upto cannot be earlier than valid from"; "Invalid Date Range";
} else { } else {
errorMessages.remove("valid_upto"); errorMessages.remove("valid_upto${entry['local_id']}");
} }
}); });
} }
@ -4325,6 +4357,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40, height: 40,
child: GestureDetector( child: GestureDetector(
onTap: () async { onTap: () async {
errorMessages.remove("valid_upto${entry['local_id']}");
await _selectValidUpToDate(context); await _selectValidUpToDate(context);
}, },
child: AbsorbPointer( child: AbsorbPointer(
@ -4351,11 +4384,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
), ),
), ),
), ),
if (errorMessages["valid_upto"] != null) ...[ if (errorMessages["valid_upto${entry['local_id']}"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
errorMessages["valid_upto"]!, errorMessages["valid_upto${entry['local_id']}"]!,
style: const TextStyle(color: Colors.red, fontSize: 10), style: GoogleFonts.poppins(color: Colors.red, fontSize: 10),
maxLines: 2, // Allow it to wrap onto two lines maxLines: 2, // Allow it to wrap onto two lines
overflow: overflow:
TextOverflow.ellipsis, // Add ellipsis if it still overflows TextOverflow.ellipsis, // Add ellipsis if it still overflows

View File

@ -111,7 +111,7 @@ class _UserListScreenState extends State<UserListScreen> {
Future<List<dynamic>> fetchUsers() async { Future<List<dynamic>> fetchUsers() async {
orgId = await getOrgId(); orgId = await getOrgId();
final String apiUrlData = '$apiUrl/api/users?org_id=$orgId'; final String apiUrlData = '$apiUrl/api/users?org_id=$orgId&for=table_view';
final String? token = await getToken(); final String? token = await getToken();
print("Fetch Users"); print("Fetch Users");
@ -294,7 +294,13 @@ class _UserListScreenState extends State<UserListScreen> {
// Refresh user list after update // Refresh user list after update
void refreshUserList() { void refreshUserList() {
setState(() { setState(() {
futureUsers = fetchUsers(); // Re-fetch users after status update futureUsers = fetchUsers();
futureUsers.then((users) {
setState(() {
allUsers = users;
});
}); // Re-fetch users after status update
// Wait for futurePlans to be fetched and update allPlans // Wait for futurePlans to be fetched and update allPlans
}); });
} }
@ -724,7 +730,9 @@ class _UserListScreenState extends State<UserListScreen> {
), ),
), ),
DataCell( DataCell(
GestureDetector( MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () { onTap: () {
handleToggleUserStatus( handleToggleUserStatus(
user['user_id'], user['user_id'],
@ -747,6 +755,7 @@ class _UserListScreenState extends State<UserListScreen> {
), ),
), ),
), ),
),
DataCell( DataCell(
UserActionsMenu( UserActionsMenu(
user: user, user: user,
@ -1146,7 +1155,6 @@ class _UserListScreenState extends State<UserListScreen> {
// ) // )
// : buildMobileCardView(paginatedUser), // : buildMobileCardView(paginatedUser),
// ), // ),
Expanded( Expanded(
child: child:
isDesktop isDesktop

View File

@ -15,6 +15,7 @@ class Plan {
final String userName; final String userName;
final String travellerName; final String travellerName;
final String approverName;
final String statusValue; final String statusValue;
final String createdOn; final String createdOn;
final String? approverId; final String? approverId;
@ -35,6 +36,7 @@ class Plan {
required this.isBillable, required this.isBillable,
required this.userName, required this.userName,
required this.travellerName, required this.travellerName,
required this.approverName,
required this.statusValue, required this.statusValue,
required this.createdOn, required this.createdOn,
this.approverId, this.approverId,
@ -44,24 +46,36 @@ class Plan {
factory Plan.fromJson(Map<String, dynamic> json) { factory Plan.fromJson(Map<String, dynamic> json) {
print('Parsing Plan from JSON: $json'); print('Parsing Plan from JSON: $json');
return Plan( return Plan(
planId: json['plan_id'], planId: json['plan_id']!.toString(),
employeeCode: json['employee_code'], employeeCode: json['employee_code']!.toString(),
tripTitle: json['trip_title'], tripTitle: json['trip_title']!.toString(),
tripType: json['trip_type_value'], tripType: json['trip_type_value']!.toString(),
approver_status: json['approver_status'], approver_status:
json["approver_status"] == null
? ''
: json['approver_status']!.toString(),
status: json['status'] == "0" ? "Inactive" : "Active", status: json['status'] == "0" ? "Inactive" : "Active",
costCenter: json['cost_center_value'] ?? '', costCenter: json['cost_center_value']!.toString(),
functionalDepartment: json['functional_department_value'] ?? '', functionalDepartment: json['functional_department_value']!.toString(),
purposeOfTravel: json['purpose_of_travel_value'] ?? '', purposeOfTravel: json['purpose_of_travel_value']!.toString(),
soNumber: json['so_number'] ?? '', soNumber: json['so_number']!.toString(),
description: json['description'] ?? '', description: json['description']!.toString(),
isBillable: json['is_billable_value'] ?? '', isBillable: json['is_billable_value']!.toString(),
userName: json["user_name"] ?? '', userName: json["user_name"]!.toString(),
travellerName: json["traveller_name"] ?? '', travellerName:
statusValue: json["status_value"] ?? '', json["traveller_name"] == null
createdOn: json["created_on"] ?? '', ? ''
approverId: json['approver_id'], : json["traveller_name"]!.toString(),
delegaterId: json['delegater_id'], approverName:
json["approver_name"] == null
? ''
: json["approver_name"]!.toString(),
statusValue: json["status_value"]!.toString(),
createdOn: json["created_on"],
approverId:
json["approver_id"] == null ? '' : json['approver_id']!.toString(),
delegaterId:
json["delegater_id"] == null ? '' : json['delegater_id']!.toString(),
); );
} }
} }

View File

@ -618,8 +618,8 @@ class ApiService {
BuildContext context, BuildContext context,
String planId, String planId,
String? approverId, String? approverId,
String? approver_status, String? delegaterId,
String? delegaterId, { String? approver_status, {
bool isViewMode = false, bool isViewMode = false,
bool isApprover = true, bool isApprover = true,
}) async { }) async {

View File

@ -21,7 +21,6 @@ class PlanPopupMenu extends StatelessWidget {
required this.layoutColor, required this.layoutColor,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Align( return Align(
@ -30,12 +29,9 @@ class PlanPopupMenu extends StatelessWidget {
color: Colors.white, color: Colors.white,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
offset: Offset(0, 30), offset: Offset(0, 30),
icon: Icon( icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 15),
Icons.more_vert, itemBuilder:
color: Color(0xFF475569), (context) => [
size: 15,
),
itemBuilder: (context) => [
CustomPopupMenuEntry( CustomPopupMenuEntry(
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4), padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
@ -48,8 +44,11 @@ class PlanPopupMenu extends StatelessWidget {
icon: Icon(Icons.remove_red_eye, size: 18), icon: Icon(Icons.remove_red_eye, size: 18),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
ApiService.viewPlan(context, plan.planId, ApiService.viewPlan(
isViewMode: true); context,
plan.planId,
isViewMode: true,
);
}, },
), ),
@ -62,7 +61,6 @@ class PlanPopupMenu extends StatelessWidget {
// isViewMode: false); // isViewMode: false);
// }, // },
// ), // ),
IconButton( IconButton(
icon: Icon(Icons.cancel_rounded, size: 18), icon: Icon(Icons.cancel_rounded, size: 18),
onPressed: () { onPressed: () {
@ -71,8 +69,11 @@ class PlanPopupMenu extends StatelessWidget {
}, },
), ),
IconButton( IconButton(
icon: Icon(Icons.download, icon: Icon(
color: Color(0xFF114D8B), size: 18), Icons.download,
color: Color(0xFF114D8B),
size: 18,
),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
apiService.getPdfDownload(plan.planId); apiService.getPdfDownload(plan.planId);
@ -87,13 +88,16 @@ class PlanPopupMenu extends StatelessWidget {
onPressed: () { onPressed: () {
showDialog( showDialog(
context: context, context: context,
builder: (context) => CommentModalList( builder:
(context) => CommentModalList(
// planId: plan.planId, // planId: plan.planId,
planId: plan.planId.toString(), planId: plan.planId.toString(),
layoutColorForUser: layoutColor!, layoutColorForUser: layoutColor!,
role: "User"), role: "User",
),
); );
}), },
),
IconButton( IconButton(
icon: const Icon( icon: const Icon(
Icons.comment, Icons.comment,
@ -103,13 +107,16 @@ class PlanPopupMenu extends StatelessWidget {
onPressed: () { onPressed: () {
showDialog( showDialog(
context: context, context: context,
builder: (context) => CommentModal( builder:
(context) => CommentModal(
// planId: plan.planId, // planId: plan.planId,
planId: plan.planId.toString(), planId: plan.planId.toString(),
layoutColorForUser: layoutColor!, layoutColorForUser: layoutColor!,
role: "Travel Agent"), role: "Travel Agent",
),
); );
}), },
),
], ],
), ),
), ),

View File

@ -101,6 +101,8 @@ flutter:
- assets/images/login/microsoft.png - assets/images/login/microsoft.png
- assets/images/IconsImg/path.png - assets/images/IconsImg/path.png
- assets/images/IconsImg/alternate.png - assets/images/IconsImg/alternate.png
- assets/images/IconsImg/ViceVersaArrow.png
- assets/images/IconsImg/Frame.png
- assets/images/IconsImg/delete.png - assets/images/IconsImg/delete.png
- assets/images/IconsImg/edit.png - assets/images/IconsImg/edit.png
- assets/images/IconsImg/planPdf_icon.png - assets/images/IconsImg/planPdf_icon.png