diff --git a/assets/images/IconsImg/Frame.png b/assets/images/IconsImg/Frame.png new file mode 100644 index 0000000..7271a16 Binary files /dev/null and b/assets/images/IconsImg/Frame.png differ diff --git a/assets/images/IconsImg/ViceVersaArrow.png b/assets/images/IconsImg/ViceVersaArrow.png new file mode 100644 index 0000000..2b08801 Binary files /dev/null and b/assets/images/IconsImg/ViceVersaArrow.png differ diff --git a/lib/Screens/approvals/approval_list.dart b/lib/Screens/approvals/approval_list.dart index 647c3b4..2a22fa3 100644 --- a/lib/Screens/approvals/approval_list.dart +++ b/lib/Screens/approvals/approval_list.dart @@ -97,7 +97,7 @@ class _ApprovalListState extends State { setState(() { futurePlans = fetchPlans(); }); - + print("Token availa"); // Wait for futurePlans to be fetched and update allPlans futurePlans.then((plans) { setState(() { @@ -186,7 +186,9 @@ class _ApprovalListState extends State { if (response.statusCode == 200) { final data = json.decode(response.body); + print('plansJson1'); List plansJson = data['data']; + print('plansJson $plansJson'); return plansJson.map((json) => Plan.fromJson(json)).toList(); } else { throw Exception('Failed to load plans'); @@ -890,6 +892,9 @@ class _ApprovalListState extends State { print( "Approver Edit2 : ${plan.delegaterId}", ); + print( + "Approver Edit3 : ${plan.approver_status}", + ); Navigator.pop( context, ); @@ -1140,6 +1145,10 @@ class _ApprovalListState extends State { 'Edit The Trip Details', onPressed: () { Navigator.pop(context); + print( + "Approver Edit3 : ${plan.approver_status}", + ); + ApiService.viewPlanForApprover( context, plan.planId, diff --git a/lib/Screens/itnerary/forex.dart b/lib/Screens/itnerary/forex.dart index 9cc1058..4cb08f5 100644 --- a/lib/Screens/itnerary/forex.dart +++ b/lib/Screens/itnerary/forex.dart @@ -94,8 +94,8 @@ class _ForexScreenState extends State { final parts = date.split('-'); if (parts.length == 3) { parsedDate = DateTime( - int.parse(parts[2]), // year - int.parse(parts[1]), // month + int.parse(parts[2]), // year + int.parse(parts[1]), // month int.parse(parts[0]), // day ); } else { @@ -356,6 +356,9 @@ class _ForexScreenState extends State { print("card - $card"); print("cash - $cash"); + _validateCardAmount(card); + _validateCashAmount(cash); + if (!isValidForexData(data)) { // && errorMessages.isNotEmpty) { print("Validation Failed: Required fields are missing."); @@ -411,7 +414,6 @@ class _ForexScreenState extends State { textControllers["_forexStartDate"]?.addListener(_onFieldChanged); textControllers["_forexEndDate"]?.addListener(_onFieldChanged); - flightFirstTripDateNotifier = ValueNotifier(null); flightLastTripDateNotifier = ValueNotifier(null); @@ -428,26 +430,62 @@ class _ForexScreenState extends State { // ✅ 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) { - textControllers["_forexStartDate"]?.text = DateFormat( - 'dd-MM-yyyy', - ).format(parsedDate); + // ----------------------------------- + + // 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( + "dd-MM-yyyy", + ).parse(flightDateStr.trim()); + textControllers["_forexStartDate"]?.text = DateFormat( + 'dd-MM-yyyy', + ).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( - "dd-MM-yyyy", - ).parse(flightLastTripDateNotifier.value ?? ''); - if (parsedEndDate != null) { - textControllers["_forexEndDate"]?.text = DateFormat( - 'dd-MM-yyyy', - ).format(parsedEndDate); + final flightDateEnd = flightFirstTripDateNotifier.value; + + if (flightDateEnd != null && flightDateEnd.trim().isNotEmpty) { + try { + final parsedDate = DateFormat( + "dd-MM-yyyy", + ).parse(flightDateEnd.trim()); + textControllers["_forexEndDate"]?.text = DateFormat( + 'dd-MM-yyyy', + ).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"); } + // 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 { print("UPDATAED SELECTION"); textControllers["_forexStartDate"] = initController("start_date"); - textControllers["_forexStartDate"]?.addListener(_onFieldChanged); // Reattach + textControllers["_forexStartDate"]?.addListener( + _onFieldChanged, + ); // Reattach textControllers["_forexEndDate"] = initController("end_date"); - textControllers["_forexEndDate"]?.addListener(_onFieldChanged); // Reattach + textControllers["_forexEndDate"]?.addListener( + _onFieldChanged, + ); // Reattach textControllers["_transport"] = initController("transport"); textControllers["_accomodation"] = initController("accommodation"); textControllers["_telephone"] = initController("telephone"); textControllers["_cardNumber"] = initController("card_number"); textControllers["_card"] = initController("deposit_on_card"); textControllers["_cash"] = initController("deposit_on_cash"); - textControllers["_deliveryLocation"] = initController("delivery_location"); + textControllers["_deliveryLocation"] = initController( + "delivery_location", + ); textControllers["_comments"] = initController("comments"); // Set dropdown values @@ -571,8 +615,8 @@ class _ForexScreenState extends State { // final startDate = DateFormat('dd/mm/yyyy').parse(startDateString); // final endDate = DateFormat('dd/mm/yyyy').parse(endDateString); - final startDate = DateFormat('dd-MM-yyyy').parse(startDateString.trim()) ; - final endDate = DateFormat('dd-MM-yyyy').parse(endDateString.trim()) ; + final startDate = DateFormat('dd-MM-yyyy').parse(startDateString.trim()); + final endDate = DateFormat('dd-MM-yyyy').parse(endDateString.trim()); print("Calculate 4"); @@ -1162,7 +1206,8 @@ class _ForexScreenState extends State { 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 ), ], ], diff --git a/lib/Screens/itnerary_list/flight_list.dart b/lib/Screens/itnerary_list/flight_list.dart index 23cce10..54919a5 100644 --- a/lib/Screens/itnerary_list/flight_list.dart +++ b/lib/Screens/itnerary_list/flight_list.dart @@ -51,10 +51,15 @@ class _FlightListWidgetState extends State { Map tempCountryMap = {}; for (var country in result) { - String city = country['City'] ?? ''; - String airport = country['Airport'] ?? ''; - String displayName = '${country['City']} - ${country['Airport']}'; - // String displayName = '${country['City']} | ${country['Airport']}'; + // String city = country['City'] ?? ''; + // String airport = 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; } @@ -346,7 +351,7 @@ class _FlightListWidgetState extends State { ), ), Expanded( - flex: 4, + flex: 5, child: Text( "Sector", style: GoogleFonts.poppins(fontSize: 11), @@ -374,13 +379,38 @@ class _FlightListWidgetState extends State { if (isDesktop) if (item["trips"] != null && item["trips"].isNotEmpty) ...item["trips"].map((trip) { + print("werewrewrTrip - $trip"); + String fromPlaceCountry = countryMap[trip["from_place"]?.toString()] ?? "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 = countryMap[trip["to_place"]?.toString()] ?? "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( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( @@ -398,36 +428,74 @@ class _FlightListWidgetState extends State { ), Expanded( flex: 4, - child: Column( + child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "$fromPlaceCountry", - // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w700, + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + "$fromcity ($fromcode)", + // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w700, + ), + ), + Text( + "$fromairport", + // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", + style: GoogleFonts.poppins( + fontSize: 10, + fontWeight: FontWeight.w400, + ), + ), + ], ), ), - Padding( - padding: const EdgeInsets.only(left: 10), - child: Image.asset( - 'assets/images/IconsImg/alternate.png', - width: 20, - height: 20, + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: Image.asset( + 'assets/images/IconsImg/Frame.png', + width: 20, + height: 20, + ), ), ), - Text( - "$toPlaceCountry", - // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w700, + 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( flex: 2, child: Text( @@ -478,6 +546,7 @@ class _FlightListWidgetState extends State { "Sector", "${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}", ), + _buildKeyValueRow( "Date", formatDate(trip["date"] ?? ""), diff --git a/lib/Screens/itnerary_list/train_list.dart b/lib/Screens/itnerary_list/train_list.dart index bf3913f..3379e45 100644 --- a/lib/Screens/itnerary_list/train_list.dart +++ b/lib/Screens/itnerary_list/train_list.dart @@ -54,7 +54,8 @@ class _TrainListWidgetState extends State { return AlertDialog( title: const Text('Select Trip Type'), content: const Text( - 'Please select a trip type before adding a Train.'), + 'Please select a trip type before adding a Train.', + ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), @@ -109,21 +110,24 @@ class _TrainListWidgetState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ MouseRegion( - cursor: widget.isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + cursor: + widget.isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: MouseRegion( - cursor: widget.isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + cursor: + widget.isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: GestureDetector( - onTap: widget.isViewMode - ? null - : () { - print("New data"); - checkClass(); - }, + onTap: + widget.isViewMode + ? null + : () { + print("New data"); + checkClass(); + }, child: Row( mainAxisSize: MainAxisSize.min, // Ensures content fits nicely @@ -137,7 +141,7 @@ class _TrainListWidgetState extends State { Icons.add_circle_sharp, size: 30, color: Color(0xFF114D8B), - ) + ), ], ), ), @@ -193,9 +197,9 @@ class _TrainListWidgetState extends State { ], ), 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 { if (hour == 24 && minute == 0) { // 24:00 is treated as 00:00 on the next day - dateTime = DateTime(now.year, now.month, now.day) - .add(const Duration(days: 1)); + dateTime = DateTime( + now.year, + now.month, + now.day, + ).add(const Duration(days: 1)); } else { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { throw FormatException("Invalid hour or minute"); @@ -356,109 +363,188 @@ class _TrainListWidgetState extends State { ), ], ), - Divider( - color: Colors.blueGrey.shade50, - ), + Divider(color: Colors.blueGrey.shade50), SizedBox(height: 4), isDesktop ? Row( - children: [ - Expanded( - flex: 2, - child: Text( - " Class", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Planned Trips", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Date", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Comments", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - ], - ) + children: [ + Expanded( + flex: 2, + child: Text( + " Class", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 4, + child: Text( + " Planned Trips", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Date", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Comments", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + ], + ) : SizedBox.shrink(), SizedBox(height: 4), isDesktop ? Row( - children: [ - Expanded( - flex: 2, - child: Text( - "${getRequestForTrainClass(item["class"]!.toString())} ", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - )), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "$fromPlaceCountry - $toPlaceCountry", - - // "${item["from_station"]!} - ${(item["to_station"])}", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - )), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "${formatDate(item["date"]!)} ${formatTime(item["time"]!)}", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), + children: [ + Expanded( + flex: 2, + child: Text( + "${getRequestForTrainClass(item["class"]!.toString())} ", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, ), ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: _buildComments( - "Comments:", item["comments"] ?? "N/A"), + ), + SizedBox(width: 10), + Expanded( + flex: 3, + + // 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"])}", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + 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( + flex: 2, + child: Text( + "${formatDate(item["date"]!)} ${formatTime(item["time"]!)}", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: _buildComments( + "Comments:", + item["comments"] ?? "N/A", + ), + ), + ], + ) : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildRow( - "Class:", - getRequestForTrainClass( - item["class"]!.toString())), - _buildRow("From:", item["from_station"]!), - _buildRow("To:", item["to_station"]!), - _buildDateTimeRow( - "Date:", - formatDate(item["date"]!), - formatTime(item["time"]!), - ), - _buildRow("Comments:", item["comments"] ?? "N/A"), - ], - ) + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildRow( + "Class:", + getRequestForTrainClass(item["class"]!.toString()), + ), + _buildRow("From:", item["from_station"]!), + _buildRow("To:", item["to_station"]!), + _buildDateTimeRow( + "Date:", + formatDate(item["date"]!), + formatTime(item["time"]!), + ), + _buildRow("Comments:", item["comments"] ?? "N/A"), + ], + ), ], ), ), @@ -487,31 +573,37 @@ class _TrainListWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: exceedsLimit - ? Tooltip( - message: wrapText(value, 50), - decoration: BoxDecoration( - color: Colors.grey.shade200, // Black background - borderRadius: BorderRadius.circular(6), - ), - textStyle: - TextStyle(color: Colors.black), // Tooltip text color - padding: EdgeInsets.all(8), - preferBelow: false, - child: Text(value.substring(0, limit) + "...", + child: + exceedsLimit + ? Tooltip( + message: wrapText(value, 50), + decoration: BoxDecoration( + color: Colors.grey.shade200, // Black background + borderRadius: BorderRadius.circular(6), + ), + textStyle: TextStyle( + color: Colors.black, + ), // Tooltip text color + padding: EdgeInsets.all(8), + preferBelow: false, + child: Text( + value.substring(0, limit) + "...", style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - fontFamily: "Archivo"), - overflow: TextOverflow.ellipsis), - ) - : Text( - value, - style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + fontFamily: "Archivo", + ), + overflow: TextOverflow.ellipsis, + ), + ) + : Text( + value, + style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, - fontFamily: "Archivo"), - ), + fontFamily: "Archivo", + ), + ), ), ], ); @@ -538,36 +630,30 @@ class _TrainListWidgetState extends State { children: [ Text( title, - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), + style: GoogleFonts.poppins(fontSize: 12, fontWeight: FontWeight.w600), ), SizedBox(width: 8), Expanded( - child: exceedsLimit - ? Tooltip( - message: wrapText(value, 50), - decoration: BoxDecoration( - color: Colors.grey.shade200, // Black background - borderRadius: BorderRadius.circular(6), - ), - textStyle: - TextStyle(color: Colors.black), // Tooltip text color - padding: EdgeInsets.all(8), - preferBelow: false, - child: Text(value.substring(0, limit) + "...", - style: GoogleFonts.poppins( - fontSize: 12, - ), - overflow: TextOverflow.ellipsis), - ) - : Text( - value, - style: GoogleFonts.poppins( - fontSize: 12, - ), - ), + child: + exceedsLimit + ? Tooltip( + message: wrapText(value, 50), + decoration: BoxDecoration( + color: Colors.grey.shade200, // Black background + borderRadius: BorderRadius.circular(6), + ), + textStyle: TextStyle( + color: Colors.black, + ), // Tooltip text color + padding: EdgeInsets.all(8), + preferBelow: false, + child: Text( + value.substring(0, limit) + "...", + style: GoogleFonts.poppins(fontSize: 12), + overflow: TextOverflow.ellipsis, + ), + ) + : Text(value, style: GoogleFonts.poppins(fontSize: 12)), ), ], ); @@ -579,18 +665,10 @@ class _TrainListWidgetState extends State { children: [ Text( title, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 12, - ), + style: TextStyle(fontWeight: FontWeight.w600, fontSize: 12), ), SizedBox(width: 8), - Expanded( - child: Text( - "$date, $time", - style: TextStyle(fontSize: 12), - ), - ), + Expanded(child: Text("$date, $time", style: TextStyle(fontSize: 12))), ], ); } diff --git a/lib/Screens/plans/create_plans.dart b/lib/Screens/plans/create_plans.dart index cee265f..aff0d40 100644 --- a/lib/Screens/plans/create_plans.dart +++ b/lib/Screens/plans/create_plans.dart @@ -1173,17 +1173,18 @@ class CreateNewPlansState extends State { print("ViewAAA - $planData"); print("Call viewPlanForApprover"); - ApiService.viewPlanForApprover( - context, - data['plan_id'], - data['approverId'], - data['delegaterId'], - data['approver_status'], - - isViewMode: false, - isApprover: true, - ); - + // ApiService.viewPlanForApprover( + // context, + // data['plan_id'], + // data['approverId'], + // data['delegaterId'], + // data['approver_status'], + // + // isViewMode: false, + // isApprover: true, + // ); + // Close loading dialog (ONLY if still mounted) + if (mounted) Navigator.of(context, rootNavigator: true).pop(); context.go('/approvallist'); } else { print("$methodName failed. Status: ${response.statusCode}"); @@ -3172,6 +3173,11 @@ class CreateNewPlansState extends State { statusValue = "Approved"; }); callApproveAPI(selectedPlanId!, planData['user_id']); + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => const SavingLoader(), + ); } else if (result is String) { // User rejected with remarks _remarksController.text = result; diff --git a/lib/Screens/userManagement/create_user/create_user.dart b/lib/Screens/userManagement/create_user/create_user.dart index d6d265f..be64bee 100644 --- a/lib/Screens/userManagement/create_user/create_user.dart +++ b/lib/Screens/userManagement/create_user/create_user.dart @@ -720,7 +720,7 @@ class _CreateUserFormDetialsState extends State { if (start_Date != null && end_Date != null && end_Date.isBefore(start_Date)) { - print("End date cannot be earlier than start date"); + print("Invalid Date Range"); return; } } catch (e) { diff --git a/lib/Screens/userManagement/create_user/office_details.dart b/lib/Screens/userManagement/create_user/office_details.dart index 6c58f9c..49b1fd2 100644 --- a/lib/Screens/userManagement/create_user/office_details.dart +++ b/lib/Screens/userManagement/create_user/office_details.dart @@ -457,7 +457,7 @@ class _OfficeDetailsState extends State { SizedBox(height: 5), // Space before error message Text( widget.errorMessages["employee_code"]!, - style: TextStyle(color: Colors.red, fontSize: 12), + style: GoogleFonts.poppins(color: Colors.red, fontSize: 12), ), ], ], diff --git a/lib/Screens/userManagement/create_user/personal_details.dart b/lib/Screens/userManagement/create_user/personal_details.dart index f3e969e..3331b66 100644 --- a/lib/Screens/userManagement/create_user/personal_details.dart +++ b/lib/Screens/userManagement/create_user/personal_details.dart @@ -802,7 +802,7 @@ class PersonalDetailsState extends State { SizedBox(height: 5), // Space before error message Text( 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 { SizedBox(height: 5), // Space before error message Text( 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 { SizedBox(height: 5), // Space before error message Text( 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 { SizedBox(height: 5), // Space before error message Text( 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 { SizedBox(height: 5), // Space before error message Text( 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 { SizedBox(height: 5), // Space before error message Text( 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 { SizedBox(height: 5), // Space before error message Text( widget.errorMessages["password"]!, - style: TextStyle(color: Colors.red, fontSize: 12), + style: GoogleFonts.poppins(color: Colors.red, fontSize: 12), ), ], ], diff --git a/lib/Screens/userManagement/create_user/traveller_details.dart b/lib/Screens/userManagement/create_user/traveller_details.dart index 2d7a6d1..c8465e5 100644 --- a/lib/Screens/userManagement/create_user/traveller_details.dart +++ b/lib/Screens/userManagement/create_user/traveller_details.dart @@ -195,7 +195,7 @@ class TravellerDetailsState extends State { end_Date != null && end_Date.isBefore(start_Date)) { 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"); } @@ -203,6 +203,11 @@ class TravellerDetailsState extends State { print("Invalid passport date format"); } + if (errorMessages.isNotEmpty) { + print("Validation failed with errors: $errorMessages"); + return false; + } + // Additional validation starts - travelDetailsData passport // DateTime? start_Date = travelDetailsData?['date_of_issue']; // DateTime? end_Date = travelDetailsData?['date_of_expiry']; @@ -1379,7 +1384,7 @@ class TravellerDetailsState extends State { SizedBox(height: 5), // Space before error message Text( errorMessages["passport_number"]!, - style: TextStyle(color: Colors.red, fontSize: 12), + style: GoogleFonts.poppins(color: Colors.red, fontSize: 12), ), ], ], @@ -1458,8 +1463,7 @@ class TravellerDetailsState extends State { // Revalidate expiry if (_selectedDateOfExpiry != null && _selectedDateOfExpiry!.isBefore(_selectedDateOfIssue!)) { - errorMessages["date_of_expiry"] = - "Expiry date cannot be earlier than Issue date"; + errorMessages["date_of_expiry"] = "Invalid Date Range"; } else { errorMessages.remove("date_of_expiry"); } @@ -1585,8 +1589,7 @@ class TravellerDetailsState extends State { if (_selectedDateOfIssue != null && _selectedDateOfExpiry!.isBefore(_selectedDateOfIssue!)) { - errorMessages["date_of_expiry"] = - "Expiry date cannot be earlier than Issue date"; + errorMessages["date_of_expiry"] = "Invalid Date Range"; } else { errorMessages.remove("date_of_expiry"); } @@ -1668,7 +1671,7 @@ class TravellerDetailsState extends State { SizedBox(height: 5), // Space before error message Text( 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 overflow: TextOverflow.ellipsis, // Add ellipsis if it still overflows @@ -2905,7 +2908,7 @@ class TravellerDetailsState extends State { SizedBox(height: 5), // Space before error message Text( errorMessages["forex_pre_paid_card_number"]!, - style: TextStyle(color: Colors.red, fontSize: 12), + style: GoogleFonts.poppins(color: Colors.red, fontSize: 12), ), ], ], @@ -4175,8 +4178,7 @@ class TravellerDetailsState extends State { // Revalidate expiry if (_selectedCheckOutDate != null && _selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) { - errorMessages["valid_upto"] = - "valid upto cannot be earlier than valid from"; + errorMessages["valid_upto"] = "Invalid Date Range"; } else { errorMessages.remove("valid_upto"); } @@ -4293,8 +4295,7 @@ class TravellerDetailsState extends State { if (_selectedCheckInDate != null && _selectedCheckOutDate!.isBefore(_selectedCheckInDate!)) { - errorMessages["valid_upto"] = - "valid upto cannot be earlier than valid from"; + errorMessages["valid_upto"] = "Invalid Date Range"; } else { errorMessages.remove("valid_upto"); } @@ -4355,7 +4356,7 @@ class TravellerDetailsState extends State { SizedBox(height: 5), // Space before error message Text( errorMessages["valid_upto"]!, - 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 overflow: TextOverflow.ellipsis, // Add ellipsis if it still overflows diff --git a/lib/Screens/userManagement/user_List.dart b/lib/Screens/userManagement/user_List.dart index ab9b547..9e10cdb 100644 --- a/lib/Screens/userManagement/user_List.dart +++ b/lib/Screens/userManagement/user_List.dart @@ -111,7 +111,7 @@ class _UserListScreenState extends State { Future> fetchUsers() async { 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(); print("Fetch Users"); @@ -294,7 +294,13 @@ class _UserListScreenState extends State { // Refresh user list after update void refreshUserList() { 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 }); } @@ -724,25 +730,28 @@ class _UserListScreenState extends State { ), ), DataCell( - GestureDetector( - onTap: () { - handleToggleUserStatus( - user['user_id'], - user['is_active'], - user, - ); - }, - child: Text( - user['is_active'] == "1" - ? "Active" - : "Inactive", - style: TextStyle( - color: - user['is_active'] == "1" - ? Colors.green - : Colors.grey, - fontFamily: "Inter", - fontWeight: FontWeight.w400, + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + handleToggleUserStatus( + user['user_id'], + user['is_active'], + user, + ); + }, + child: Text( + user['is_active'] == "1" + ? "Active" + : "Inactive", + style: TextStyle( + color: + user['is_active'] == "1" + ? Colors.green + : Colors.grey, + fontFamily: "Inter", + fontWeight: FontWeight.w400, + ), ), ), ), @@ -1146,37 +1155,36 @@ class _UserListScreenState extends State { // ) // : buildMobileCardView(paginatedUser), // ), - Expanded( child: - isDesktop - ? (searchController.text.isNotEmpty && - filteredUsers.isEmpty - ? Center( - child: Text( - "No users found", - style: GoogleFonts.poppins( - fontSize: 14, - color: Colors.grey, - ), - ), - ) - : SingleChildScrollView( - scrollDirection: Axis.vertical, - child: table, - )) - : (searchController.text.isNotEmpty && - filteredUsers.isEmpty - ? Center( - child: Text( - "No users found", - style: GoogleFonts.poppins( - fontSize: 14, - color: Colors.grey, - ), - ), - ) - : buildMobileCardView(paginatedUser)), + isDesktop + ? (searchController.text.isNotEmpty && + filteredUsers.isEmpty + ? Center( + child: Text( + "No users found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey, + ), + ), + ) + : SingleChildScrollView( + scrollDirection: Axis.vertical, + child: table, + )) + : (searchController.text.isNotEmpty && + filteredUsers.isEmpty + ? Center( + child: Text( + "No users found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey, + ), + ), + ) + : buildMobileCardView(paginatedUser)), // child: isDesktop // ? SingleChildScrollView( // scrollDirection: Axis.vertical, diff --git a/lib/data/models/plan.dart b/lib/data/models/plan.dart index be2f706..ce2cdec 100644 --- a/lib/data/models/plan.dart +++ b/lib/data/models/plan.dart @@ -44,24 +44,32 @@ class Plan { factory Plan.fromJson(Map json) { print('Parsing Plan from JSON: $json'); return Plan( - planId: json['plan_id'], - employeeCode: json['employee_code'], - tripTitle: json['trip_title'], - tripType: json['trip_type_value'], - approver_status: json['approver_status'], + planId: json['plan_id']!.toString(), + employeeCode: json['employee_code']!.toString(), + tripTitle: json['trip_title']!.toString(), + tripType: json['trip_type_value']!.toString(), + approver_status: + json["approver_status"] == null + ? '' + : json['approver_status']!.toString(), status: json['status'] == "0" ? "Inactive" : "Active", - costCenter: json['cost_center_value'] ?? '', - functionalDepartment: json['functional_department_value'] ?? '', - purposeOfTravel: json['purpose_of_travel_value'] ?? '', - soNumber: json['so_number'] ?? '', - description: json['description'] ?? '', - isBillable: json['is_billable_value'] ?? '', - userName: json["user_name"] ?? '', - travellerName: json["traveller_name"] ?? '', - statusValue: json["status_value"] ?? '', - createdOn: json["created_on"] ?? '', - approverId: json['approver_id'], - delegaterId: json['delegater_id'], + costCenter: json['cost_center_value']!.toString(), + functionalDepartment: json['functional_department_value']!.toString(), + purposeOfTravel: json['purpose_of_travel_value']!.toString(), + soNumber: json['so_number']!.toString(), + description: json['description']!.toString(), + isBillable: json['is_billable_value']!.toString(), + userName: json["user_name"]!.toString(), + travellerName: + json["traveller_name"] == null + ? '' + : json["traveller_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(), ); } } diff --git a/lib/services/apiService.dart b/lib/services/apiService.dart index dca8153..f74b9c7 100644 --- a/lib/services/apiService.dart +++ b/lib/services/apiService.dart @@ -618,8 +618,8 @@ class ApiService { BuildContext context, String planId, String? approverId, - String? approver_status, - String? delegaterId, { + String? delegaterId, + String? approver_status, { bool isViewMode = false, bool isApprover = true, }) async { diff --git a/pubspec.yaml b/pubspec.yaml index 58aee17..a8f42c4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -101,6 +101,8 @@ flutter: - assets/images/login/microsoft.png - assets/images/IconsImg/path.png - assets/images/IconsImg/alternate.png + - assets/images/IconsImg/ViceVersaArrow.png + - assets/images/IconsImg/Frame.png - assets/images/IconsImg/delete.png - assets/images/IconsImg/edit.png - assets/images/IconsImg/planPdf_icon.png