From 35229fa7553c746f0e2b553b57a842fbda98c794 Mon Sep 17 00:00:00 2001 From: venba-Inspriron-3558 Date: Tue, 15 Jul 2025 15:58:38 +0530 Subject: [PATCH] july 1 to july 15 --- assets/images/IconsImg/Domestic.png | Bin 0 -> 6173 bytes assets/images/IconsImg/Domestic_new.png | Bin 0 -> 2115 bytes assets/images/IconsImg/Domestic_old.png | Bin 0 -> 11751 bytes assets/images/IconsImg/International.png | Bin 0 -> 6059 bytes assets/images/IconsImg/International_new.png | Bin 0 -> 1909 bytes assets/images/IconsImg/International_old.png | Bin 0 -> 13256 bytes lib/Screens/allTrips/list_all_plans.dart | 165 ++++- lib/Screens/approvals/approval_list.dart | 13 +- lib/Screens/costCenter/costCenterDetails.dart | 50 +- lib/Screens/costCenter/costCenter_list.dart | 30 +- .../dashboard/status_dashboard (copy).dart | 423 ++++++++++++ lib/Screens/dashboard/status_dashboard.dart | 622 +++++++++++++++--- lib/Screens/department/departmentDetails.dart | 40 +- lib/Screens/department/department_list.dart | 30 +- lib/Screens/group/groupDetails.dart | 81 ++- lib/Screens/group/groupList.dart | 80 ++- lib/Screens/hotels/hotelsDetails.dart | 52 +- lib/Screens/hotels/hotels_list.dart | 30 +- lib/Screens/itnerary/accomodations.dart | 146 +++- lib/Screens/itnerary/bus.dart | 12 +- lib/Screens/itnerary/forex.dart | 5 +- lib/Screens/itnerary/miscellaneous.dart | 76 ++- lib/Screens/itnerary/taxi.dart | 115 +++- lib/Screens/itnerary/train.dart | 173 ++++- lib/Screens/itnerary/visa.dart | 118 +++- lib/Screens/myTemplates/template.dart | 27 +- lib/Screens/myTemplates/templateForex.dart | 62 +- lib/Screens/myTemplates/templatesList.dart | 26 +- lib/Screens/organization/mailSettings.dart | 48 +- lib/Screens/organization/orgSetup.dart | 2 +- lib/Screens/organization/org_List.dart | 2 +- lib/Screens/perdiem_amount/forexDetails.dart | 45 +- lib/Screens/perdiem_amount/forex_list.dart | 40 +- lib/Screens/plans/create_plans.dart | 57 +- lib/Screens/plans/list_plans.dart | 36 +- lib/Screens/policy/policy.dart | 130 +++- lib/Screens/policy/policyCriteria.dart | 76 ++- lib/Screens/policy/policy_list.dart | 64 +- .../purpose_of_travel_details.dart | 39 +- .../purpose_of_travel_list.dart | 29 +- lib/Screens/reports/advancePurchase.dart | 208 +++--- lib/Screens/reports/misAir.dart | 123 ++-- lib/Screens/reports/misForex.dart | 111 ++-- lib/Screens/reports/misHotel.dart | 259 ++++---- lib/Screens/reports/servicesAnalysis.dart | 139 ++-- lib/Screens/traveller/travellerDetails.dart | 39 +- lib/Screens/traveller/travellerList.dart | 30 +- .../createTravelAgent.dart | 5 +- .../listTravelAgent.dart | 72 +- .../personalDetailsTravelAgent.dart | 182 +++-- .../create_user/create_user.dart | 119 ++-- .../create_user/office_details.dart | 388 ++++++++++- .../create_user/personal_details.dart | 257 ++++++-- .../create_user/traveller_details.dart | 249 ++++++- lib/Screens/userManagement/user_List.dart | 38 +- lib/app.dart | 4 +- lib/config/apiUrl.dart | 5 +- lib/widgets/custom_user_form.dart | 27 +- lib/widgets/custom_user_travel.dart | 47 +- pubspec.yaml | 7 + 60 files changed, 4133 insertions(+), 1120 deletions(-) create mode 100644 assets/images/IconsImg/Domestic.png create mode 100644 assets/images/IconsImg/Domestic_new.png create mode 100644 assets/images/IconsImg/Domestic_old.png create mode 100644 assets/images/IconsImg/International.png create mode 100644 assets/images/IconsImg/International_new.png create mode 100644 assets/images/IconsImg/International_old.png create mode 100644 lib/Screens/dashboard/status_dashboard (copy).dart diff --git a/assets/images/IconsImg/Domestic.png b/assets/images/IconsImg/Domestic.png new file mode 100644 index 0000000000000000000000000000000000000000..06c4dd3781827ab7303d866287a7f4ab092536bb GIT binary patch literal 6173 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 vPM57Cz00000NkvXXu0mjfjwZJ( literal 0 HcmV?d00001 diff --git a/assets/images/IconsImg/Domestic_new.png b/assets/images/IconsImg/Domestic_new.png new file mode 100644 index 0000000000000000000000000000000000000000..c5abd404b73c1b11f1e9b7c9e02ddbabc5ad5dc9 GIT binary patch literal 2115 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 literal 0 HcmV?d00001 diff --git a/assets/images/IconsImg/Domestic_old.png b/assets/images/IconsImg/Domestic_old.png new file mode 100644 index 0000000000000000000000000000000000000000..f8002ceb84e2e6353934ecaa206e235f6f780d5e GIT binary patch literal 11751 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 literal 0 HcmV?d00001 diff --git a/assets/images/IconsImg/International_new.png b/assets/images/IconsImg/International_new.png new file mode 100644 index 0000000000000000000000000000000000000000..c67a960c6935b5281050924bc19fad99df7db864 GIT binary patch literal 1909 zcmV-*2a5QKP)@~0drDELIAGL9O(c600d`2O+f$vv5yPQ<&)eP6yWT9T+@>pF1^J01V8F^-e@Y z&gl-3d`5f$AIRF>)_}gF6+l{n_&Yd&)14+P0P_=OOp*rZgE2=${&8{+!b>9i7#4)< z5oS!2jxiwOyKwsC1uPINa9#ZOdH~=564Bg$N{*pedV?&xkU&eL0@s09*S!KX^|9j! zmy{KHumsGWC77hX)+IxjgzSLaV&L!k11t%%5pGawviO$L*gGK`X91u+%LMG`9i#(!1dnoIV|qJo~kq zxCP=;+@c&|Cd#P`fl`z?5TZ=_V`Vz9Vz;n(2bO?h!i~LWL}K5&0sY}!SY@K-p18pz zVz)r^4we8@NEV>21SGd^i60lC@w^EqPxeJmtl>6Y9MScZ0_7fE_-E$;=0uqA#^0M@ z>|sI{$)b6xjKQhS46BJ>H}>Ap|60bV&4jeZ#YN%0J#1j$2&{eOKlR{)`7!r~OmyS< zxu!Z>PmX1gWgw`w*zB;Iy^vJNt6A?Qb!IEmS7Y!%=?%oexxAWT6T+y8 zrat0Sh_Q>c$$j1wr9+!ZfD?a_8?ZIlsUX6x`^$7BSpc6tj9mK|Tyx|H6vyjm@`*4;M$!oGLXZWYN z^d#y~1Y`7iPLc6uGmbW_PggP{!V=+RG4Wg2g%EV+*};_fFXX#}qAFz*`!SE11xo=r z;nO3+)@{pco-1&Eo%Go;!sbffm{0%eW{s^AFE(Z^PJ6u&bQ4y2)owkJi*uLVp~b#xye=!O4zhBwq4WBKDD_0OxYHIspH*b&O%8mp1lz zDYt1!zs=o(V@T@>DL*1vK+>Qmg^xs`Nq`gtXBzRi<3gz?f#~c(VhE3lRtBb5NS1>R zfrWfs4;avP)dbK)Gj%&wWx_mmdNqi+;rg*j6X~aWcolN+h!Xx~?oAteZvmhj5rem9 z>(6|N00J9_BJw@FCTWb8^+duKs7#EYEJA*}2pF@idDvjs9c&3*z;Lb)%SSY4yY=hA z29(kW2*sI0?qnml4iNigPP2uC3b)M#!I)y-N9b7<9`?K7Nt(c4Liv%eU_KNPCd0a2 zD+3_rtE&@gNb^poO_FjhQWnEXkxTaJ->&rTs2Z!YgJTLRozFDV2Sg_k;qyQjrqnGi_O`Uup@VNobe-0o~+SL`s^xeE&xTulDha<7-V>Jz*k!ahtiPrAjwDMhGZv-Ev_qE0fB>jpRXMAIhLiTY!y} zDvZaq#5blb)iW=D7Szfu2of$V+b0MYv<0M4wU5$=#tBPPgZgQ9r4ww*vCpB)ZUw|; zyU8uLVhjq~0^E8H&AX?R?R?|oA@ zqk+%Kg^wj>sTRrKXgA^kETyBY=Mu5|#K%LsBR`Bxo`d{Z6BjIr`F?&N#2mM0sX}&F v$&Ug?#Xx^Vnjh}??7@%1aCqr+{#^JUtCc_4XZ#`x00000NkvXXu0mjfa|V$T literal 0 HcmV?d00001 diff --git a/assets/images/IconsImg/International_old.png b/assets/images/IconsImg/International_old.png new file mode 100644 index 0000000000000000000000000000000000000000..59ae90f9330b92bbe2c05489eb5620e1083942b3 GIT binary patch literal 13256 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 { // ), SizedBox(height: adjHgt / 4), Text( - " No Trips Found", + " No Data Found", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, - fontWeight: FontWeight.w500, - color: Colors.black54, + fontWeight: FontWeight.bold, + color: Colors.grey, ), ), ], @@ -1187,11 +1187,156 @@ class _ListAllPlansState extends State { ), Column( children: [ - PlanPopupMenu( - plan: plan, - deletePlan: deletePlan, - apiService: apiService, - layoutColor: layoutColor, + // PlanPopupMenu( + // plan: plan, + // deletePlan: deletePlan, + // apiService: apiService, + // layoutColor: layoutColor, + // ), + PopupMenuButton( + color: Colors.white, + padding: EdgeInsets.zero, + offset: Offset(0, 30), + icon: Icon( + Icons.more_vert, + color: Color(0xFF475569), + size: 14, + ), + itemBuilder: + (context) => [ + CustomPopupMenuEntry( + child: Container( + padding: + EdgeInsets.symmetric( + horizontal: 8, + vertical: 8, + ), + child: Row( + mainAxisSize: + MainAxisSize.min, + mainAxisAlignment: + MainAxisAlignment + .center, + children: [ + IconButton( + icon: Icon( + Icons + .remove_red_eye, + color: Color( + 0xFF475569, + ), + size: 18, + ), + tooltip: + 'View The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); // Close popup manually + ApiService.viewPlan( + context, + plan.planId, + isViewMode: + true, + ); + }, + ), + if (plan.statusValue == + "Pending Approval" || + plan.statusValue == + "Partially Approved") + IconButton( + icon: Image.asset( + 'assets/images/IconsImg/edit.png', + width: 20, + height: 15, + ), + tooltip: + 'Edit The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); + ApiService.viewPlan( + context, + plan.planId, + isViewMode: + false, + ); + }, + ), + IconButton( + icon: Icon( + Icons + .cancel_rounded, + size: 18, + ), + tooltip: + 'Cancellation The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); + deletePlan( + plan.planId, + ); + }, + ), + IconButton( + icon: Icon( + Icons.download, + color: Color( + 0xFF114D8B, + ), + size: 18, + ), + tooltip: + 'Download The PDF', + onPressed: () { + Navigator.pop( + context, + ); + apiService + .getPdfDownload( + plan.planId, + ); + }, + ), + IconButton( + icon: const Icon( + Icons.comment, + color: Color( + 0xFF475569, + ), + size: 11, + ), + tooltip: + 'Trip Comments', + onPressed: () { + showDialog( + context: + context, + builder: + ( + context, + ) => CommentModalList( + // planId: plan.planId, + planId: + plan.planId + .toString(), + layoutColorForUser: + layoutColor!, + role: + "Admin", + ), + ); + }, + ), + ], + ), + ), + ), + ], ), ], ), @@ -1311,7 +1456,7 @@ class _ListAllPlansState extends State { filteredPlans.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, @@ -1326,7 +1471,7 @@ class _ListAllPlansState extends State { filteredPlans.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, diff --git a/lib/Screens/approvals/approval_list.dart b/lib/Screens/approvals/approval_list.dart index f780837..05e1b14 100644 --- a/lib/Screens/approvals/approval_list.dart +++ b/lib/Screens/approvals/approval_list.dart @@ -858,15 +858,12 @@ class _ApprovalListState extends State { // fontWeight: FontWeight.bold, // color: Colors.redAccent)), SizedBox(height: adjHgt / 4), - Text( - " No Trips Pending For Your Approvals", - + Text("No Data Found", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, - // fontFamily: "Inter", - fontWeight: FontWeight.w500, - color: Colors.black54, + fontWeight: FontWeight.bold, + color: Colors.grey, ), ), ], @@ -1688,7 +1685,7 @@ class _ApprovalListState extends State { filteredPlans.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, @@ -1703,7 +1700,7 @@ class _ApprovalListState extends State { filteredPlans.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, diff --git a/lib/Screens/costCenter/costCenterDetails.dart b/lib/Screens/costCenter/costCenterDetails.dart index 697e3c8..9286603 100644 --- a/lib/Screens/costCenter/costCenterDetails.dart +++ b/lib/Screens/costCenter/costCenterDetails.dart @@ -50,6 +50,7 @@ class CostCenterDataState extends State { String? userId; int? costcenterDataId; late String isActive = "1"; + bool isDisable = false; List dataHeader = ["name", "description"]; @@ -163,9 +164,12 @@ class CostCenterDataState extends State { userId = await getUserId(); setState(() { + isDisable = true; // This triggers UI rebuild with error messages if (validateData()) { postCostCenterData(); + }else{ + isDisable = false; } }); @@ -221,22 +225,38 @@ class CostCenterDataState extends State { print("Update - Response: ${response.body}"); _clearError(); widget.fetchGetCostCenter(); - Navigator.of(context).pop(); + if (context.mounted) { + Navigator.of(context).pop(); // Close modal only if mounted + } + setState(() { + isDisable = false; + }); break; case 201: print("Save - Response: ${response.body}"); _clearError(); await widget.fetchGetCostCenter(); - Navigator.of(context).pop(); + if (context.mounted) { + Navigator.of(context).pop(); // Close modal only if mounted + } + setState(() { + isDisable = false; + }); break; default: print("Failed to submit costcenter. Status: ${response.statusCode}"); print("Error: ${response.body}"); + setState(() { + isDisable = false; + }); } } catch (e) { print(" Error submitting plan: $e"); + setState(() { + isDisable = false; + }); } } @@ -406,11 +426,27 @@ class CostCenterDataState extends State { // ), SizedBox( child: ElevatedButton( - onPressed: () { - handleSubmit(); - // You can get text from commentController.text - // Navigator.of(context).pop(); // Close the modal - }, + onPressed: isDisable + ? null + : () async { + setState(() { + isDisable = true; + }); + + await handleSubmit(); + // You can get text from commentController.text + // Navigator.of(context).pop(); // Close the modal + + // Optional: re-enable only on error + // setState(() { + // isDisable = false; + // }); + }, + // onPressed: () { + // handleSubmit(); + // // You can get text from commentController.text + // // Navigator.of(context).pop(); // Close the modal + // }, style: ElevatedButton.styleFrom( backgroundColor: widget.layoutColor, shape: RoundedRectangleBorder( diff --git a/lib/Screens/costCenter/costCenter_list.dart b/lib/Screens/costCenter/costCenter_list.dart index a428070..6450262 100644 --- a/lib/Screens/costCenter/costCenter_list.dart +++ b/lib/Screens/costCenter/costCenter_list.dart @@ -132,6 +132,7 @@ class CostCenterListState extends State { } Future> fetchGetCostCenter() async { + // return []; final String apiUrlData = '$apiUrl/api/getCostCenterMaster?for=table_view'; final String? token = await getToken(); @@ -285,7 +286,7 @@ class CostCenterListState extends State { isDesktop: isDesktop, breadcrumbItems: [ BreadcrumbItem( - title: 'Organization Settings', + title: 'Org Settings', tooltip: 'Go To Organization Settings', onTap: (context) { context.go("/OrganizationSettings"); @@ -455,6 +456,7 @@ class CostCenterListState extends State { FutureBuilder>( future: futureCostCenter, builder: (context, snapshot) { + final adjHgt = MediaQuery.of(context).size.height; if (futureCostCenter == null) { return CircularProgressIndicator(); } @@ -480,9 +482,9 @@ class CostCenterListState extends State { // fontWeight: FontWeight.bold, // color: Colors.redAccent), // ), - const SizedBox(height: 8), + SizedBox(height: adjHgt / 4), Text( - "No CostCenter Available ", + "No Data Found ", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, @@ -491,15 +493,15 @@ class CostCenterListState extends State { ), ), const SizedBox(height: 20), - Text( - "Please Create CostCenter Details", - textAlign: TextAlign.center, - style: GoogleFonts.poppins( - fontSize: 16, - color: Colors.grey, - ), - ), - const SizedBox(height: 20), + // Text( + // "Please Create CostCenter Details", + // textAlign: TextAlign.center, + // style: GoogleFonts.poppins( + // fontSize: 16, + // color: Colors.grey, + // ), + // ), + // const SizedBox(height: 20), ], ), ), @@ -906,7 +908,7 @@ class CostCenterListState extends State { filteredCostCenter.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, @@ -921,7 +923,7 @@ class CostCenterListState extends State { filteredCostCenter.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, diff --git a/lib/Screens/dashboard/status_dashboard (copy).dart b/lib/Screens/dashboard/status_dashboard (copy).dart new file mode 100644 index 0000000..9cbe615 --- /dev/null +++ b/lib/Screens/dashboard/status_dashboard (copy).dart @@ -0,0 +1,423 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:html' as html; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:frontend/routes/custom_router.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:responsive_builder/responsive_builder.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../config/apiUrl.dart'; +import '../../routes/custom_appBar.dart'; +import '../../routes/custom_drawer.dart'; +import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; +import '../../utils/pagination.dart'; + +class StatusDashboard extends StatefulWidget { + const StatusDashboard({super.key}); + + @override + StatusDashboardState createState() => StatusDashboardState(); +} + +class StatusDashboardState extends State { + Map? apiData; + String? organizationId; + late bool _dialogShown = false; + late StreamSubscription _popStateListener; + + @override + void initState() { + super.initState(); + _checkAuthAndLoadData(); + + checkbackbutton(); + + // loadDashboardData(); + } + + void checkbackbutton() async { + // Push a dummy state so back button triggers popstate instead of navigating + html.window.history.pushState(null, 'home', html.window.location.href); + + _popStateListener = html.window.onPopState.listen((event) { + if (!_dialogShown && mounted) { + _showBackConfirmationDialog(); + } + + // Re-push to prevent leaving + html.window.history.pushState(null, 'home', html.window.location.href); + }); + } + + @override + void dispose() { + _popStateListener.cancel(); // ✅ Remove the browser popstate listener + super.dispose(); + } + + void _showBackConfirmationDialog() { + if (!mounted) return; + + _dialogShown = true; + + showDialog( + context: context, + builder: + (context) => AlertDialog( + title: Text("Confirm"), + content: Text("Do you want to logout?"), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); // Close dialog + _dialogShown = false; + }, + child: Text("Cancel"), + ), + TextButton( + onPressed: () async { + Navigator.pop(context); // Close dialog + _dialogShown = false; + await _logoutAndRedirect(context); + }, + child: Text("Logout"), + ), + ], + ), + ); + } + + Future _logoutAndRedirect(BuildContext context) async { + print("logue 0"); + + // Example: clear session or shared preferences + final prefs = await SharedPreferences.getInstance(); + await prefs.clear(); + + context.go("/"); + + print("logue 1"); + } + + void _checkAuthAndLoadData() async { + final String? token = await getToken(); // Your async function to get token + + if (token == null || token.isEmpty) { + // Token doesn't exist → redirect to login + context.go( + "/", + ); // or use: router.go("/") if you're using `GoRouter` directly + return; + } + + WidgetsBinding.instance.addPostFrameCallback((_) { + checkbackbutton(); + }); + // If token exists, load the dashboard data + loadDashboardData(); + } + + Future loadDashboardData() async { + try { + final data = await fetchStatusDashboard(); + setState(() { + apiData = data; + }); + } catch (e) { + print("Error loading dashboard: $e"); + } + } + + Future getToken() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('auth_token'); + } + + Future getOrgId() async { + final prefs = await SharedPreferences.getInstance(); + final String? userDataString = prefs.getString('user_data'); + + if (userDataString != null) { + try { + final Map userData = jsonDecode(userDataString); + return userData["org_id"]?.toString(); + } catch (e) { + return null; + } + } + return null; + } + + Future> fetchStatusDashboard() async { + organizationId = await getOrgId(); + + final String apiUrlData = + '$apiUrl/api/plans/statusDashboard?org_id=$organizationId'; + final String? token = await getToken(); + + print("Fetch StatusDashboard -- 2KN Here : $token"); + + if (token == null) { + throw Exception('Token not found. Please log in.'); + } + + final response = await http.get( + Uri.parse(apiUrlData), + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + ); + print("called api : $apiUrlData"); + if (response.statusCode == 200) { + final apiData = json.decode(response.body); + print("Fetch StatusDashboard -- Reponse Here : $apiData"); + return apiData; // Returning raw JSON list + } else { + throw Exception('Failed to load users'); + } + } + + Color getStatusColor(String status) { + if (status == "Domestic") return Colors.white; + if (status == "International") return Colors.white; + if (status == "Partially Approved") return Colors.yellow.shade100; + if (status == "Pending Approval") return Colors.greenAccent.shade100; + if (status == "Approved") return Colors.green.shade100; + if (status == "Completed") return Colors.green.shade500; + if (status == "Rejected") return Colors.red.shade100; + if (status == "Cancelled") return Colors.red.shade200; + return Colors.grey.shade100; + } + + IconData getStatusIcon(String title) { + switch (title) { + case "Domestic": + return Icons.directions_bus_filled_outlined; + case "International": + return Icons.airplanemode_active; + case "Partially Approved": + return Icons.pending; + case "Approved": + return Icons.check_circle_outline; + case "Completed": + return Icons.done_all; + case "Rejected": + return Icons.cancel_outlined; + case "Cancelled": + return Icons.cancel_schedule_send_outlined; + + default: + return Icons.info_outline; + } + } + + @override + Widget build(BuildContext context) { + final typeBasedCount = List>.from( + (apiData?['data']?['typeBasedCount']) ?? [], + ); + + print("apiData - => $apiData"); + print("typeBasedCount => $typeBasedCount"); + + final statusBasedCount = List>.from( + (apiData?['data']?['statusBasedCount']) ?? [], + ); + print("statusBasedCount - => $statusBasedCount"); + // 👇 Local function to create the card widget + Widget buildInfoCard(String title, int count, double width) { + print('title $title'); + final color = getStatusColor(title); + final icon = getStatusIcon(title); + return Card( + elevation: 3, + color: color, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Container( + width: width, + padding: const EdgeInsets.all(12), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + size: 32, + color: + (title == 'Domestic' || title == 'International') + ? Colors.green + : Colors.black54, + ), // 👈 Add Icon here + const SizedBox(height: 8), + Text( + title, + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: + (title == 'Domestic' || title == 'International') + ? 16 + : 14, + ), + ), + const SizedBox(height: 8), + Text( + count.toString(), + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + // color: Colors.blue, + ), + ), + ], + ), + ), + ); + } + + void _handleBackButton() { + final location = GoRouterState.of(context).uri.toString(); + + print("location - $location"); + if (location.contains('/StatusDashboard')) { + // Do nothing or show "Press again to exit" toast + print("Blocked back on dashboard"); + } else { + print("dashboard .."); + } + } + + return ResponsiveBuilder( + builder: (context, sizingInfo) { + bool isDesktop = + sizingInfo.deviceScreenType == DeviceScreenType.desktop; + + return PopScope( + canPop: false, // Allow back navigation only if not login screen + onPopInvokedWithResult: (didPop, result) { + if (didPop) return; + _handleBackButton(); // Show exit confirmation dialog + }, + child: Scaffold( + backgroundColor: const Color(0xFFf5f5f5), + appBar: CustomAppBar(isDesktop: isDesktop), + drawer: CustomDrawer(isDesktop: false), + body: Padding( + padding: + isDesktop + ? EdgeInsets.symmetric( + horizontal: + MediaQuery.of(context).size.width * + 0.1, // 30% of screen width as horizontal padding + vertical: 10, // 5% of screen height as vertical padding + ) + : EdgeInsets.all(0), + child: LayoutBuilder( + builder: (context, constraints) { + return SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: constraints.maxHeight, + ), + child: IntrinsicHeight( + // Only needed if child layout depends on height + child: Container( + decoration: BoxDecoration( + color: + isDesktop + ? Colors.white + : const Color(0xFFFCFCFC), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(30.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Wrap( + spacing: 10, + runSpacing: 10, + children: + typeBasedCount.map((item) { + double cardWidth = + isDesktop + ? (MediaQuery.of( + context, + ).size.width * + 0.75 - + 10) / + 2 // 80% width padding adjusted + : MediaQuery.of( + context, + ).size.width - + 24; // full width with padding + + return SizedBox( + width: cardWidth, + child: buildInfoCard( + item['value'], + item['count'], + cardWidth, + ), + ); + }).toList(), + ), + const SizedBox(height: 20), + Wrap( + spacing: 10, + runSpacing: 10, + children: + statusBasedCount.map((item) { + double cardWidth = + isDesktop + ? (MediaQuery.of( + context, + ).size.width * + 0.90 - + 50) / + 6 // desktop layout: 6 cards per row + : MediaQuery.of( + context, + ).size.width - + 24; // mobile: full width + + return SizedBox( + width: cardWidth, + child: buildInfoCard( + item['value'], + item['count'], + cardWidth, + ), + ); + }).toList(), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + }, + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/Screens/dashboard/status_dashboard.dart b/lib/Screens/dashboard/status_dashboard.dart index 9cbe615..93ea009 100644 --- a/lib/Screens/dashboard/status_dashboard.dart +++ b/lib/Screens/dashboard/status_dashboard.dart @@ -31,6 +31,34 @@ class StatusDashboardState extends State { String? organizationId; late bool _dialogShown = false; late StreamSubscription _popStateListener; + String selectedView = 'Today'; + String AccessKeyFlag = "Both"; + Map? currentData; + List typeData = []; + List statusData = []; + List flightData = []; + List accommodationData = []; + List forexData = []; + + final categoryIcons = { + "flight": Icons.flight, + "accommodation": Icons.hotel_outlined, + "forex": Icons.attach_money, + }; + + List statusLabels = [ + "Pending Approval", + "Partially Approved", + "Approved", + "Rejected", + "Cancelled" + ]; + + // Extract counts for "Both" section + List getStatusValues(Map serviceData) { + final both = serviceData['Both'] ?? {}; + return statusLabels.map((label) => (both[label] ?? 0) as int).toList(); + } @override void initState() { @@ -231,7 +259,82 @@ class StatusDashboardState extends State { final statusBasedCount = List>.from( (apiData?['data']?['statusBasedCount']) ?? [], ); + + final statusBasedTodayCount = List>.from( + (apiData?['data']?['statusBasedTodayCount']) ?? [], + ); + + final statusBasedWeeklyCount = List>.from( + (apiData?['data']?['statusBasedWeeklyCount']) ?? [], + ); + + final typeBasedTodayCount = List>.from( + (apiData?['data']?['typeBasedTodayCount']) ?? [], + ); + + final typeBasedWeeklyCount = List>.from( + (apiData?['data']?['typeBasedWeeklyCount']) ?? [], + ); + + final typeTodayBasedCount = List>.from( + (apiData?['data']?['typeTodayBasedCount']) ?? [], + ); + + final typeWeeklyBasedCount = List>.from( + (apiData?['data']?['typeWeeklyBasedCount']) ?? [], + ); + + final statusTodayBasedCount = List>.from( + (apiData?['data']?['statusTodayBasedCount']) ?? [], + ); + + final statusWeeklyBasedCount = List>.from( + (apiData?['data']?['statusWeeklyBasedCount']) ?? [], + ); + + final List todayList = List>.from( + apiData?['data']?['todayTripCounts'] ?? [], + ); + + final List weekList = List>.from( + apiData?['data']?['weekTripCounts'] ?? [], + ); + + // Merge all maps in the list into one map + Map todayBasedCount = {}; + Map weekBasedCount = {}; + + for (final item in todayList) { + todayBasedCount.addAll(item); + } + + for (final item in weekList) { + weekBasedCount.addAll(item); + } + + setState(() { + // currentData = selectedView == "Today" ? todayBasedCount : weekBasedCount; + typeData = selectedView == "Today" + ? typeBasedTodayCount + : typeBasedWeeklyCount ; + statusData = selectedView == "Today" + ? statusBasedTodayCount + : statusBasedWeeklyCount ; + + flightData = selectedView == "Today" + ? getStatusValues(todayBasedCount['flight'] ?? {}) + : getStatusValues(weekBasedCount['flight'] ?? {}); + accommodationData = selectedView == "Today" + ? getStatusValues(todayBasedCount['acomodation'] ?? {}) + : getStatusValues(weekBasedCount['acomodation'] ?? {}); + forexData = selectedView == "Today" + ? getStatusValues(todayBasedCount['forex'] ?? {}) + : getStatusValues(weekBasedCount['forex'] ?? {}); + }); + + print("statusBasedCount - => $statusBasedCount"); + print("Current Data - => $currentData"); // 👇 Local function to create the card widget Widget buildInfoCard(String title, int count, double width) { print('title $title'); @@ -265,6 +368,7 @@ class StatusDashboardState extends State { (title == 'Domestic' || title == 'International') ? 16 : 14, + color: Colors.black87, ), ), const SizedBox(height: 8), @@ -293,6 +397,317 @@ class StatusDashboardState extends State { print("dashboard .."); } } + String capitalize(String s) => s[0].toUpperCase() + s.substring(1); + + Widget toggleChip(String label) { + bool isSelected = selectedView == label; + + return GestureDetector( + onTap: () { + setState(() { + selectedView = label; + }); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: isSelected ? const Color(0xFF003A78) : Colors.transparent, + borderRadius: BorderRadius.circular(20), + ), + alignment: Alignment.center, + height: 36, + child: Text( + label, + style: GoogleFonts.poppins( + fontSize: 10, + color: isSelected ? Colors.white : Colors.black, + fontWeight: FontWeight.w700, + ), + ), + ), + ); + } + + Widget buildTopCard({ + // required IconData icon, + required Color color, + required String label, + required int count, + required Color bgColor, + }) { + return Container( + padding: const EdgeInsets.all(1), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(1), + ), + child: Column( + children: [ + Tooltip( + message: label , + child: Image.asset( + label == 'Domestic' + ? 'assets/images/IconsImg/Domestic_new.png' + : 'assets/images/IconsImg/International_new.png', + // width: 65, + // height: label == 'Domestic' ? 37 : 40, + ), + ), + // Icon(icon, color: color, size: 40), + const SizedBox(height: 10), + Text( + count.toString(), + style: GoogleFonts.poppins( + fontSize: 28, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 5), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(20), + ), + child: Text( + label, + style: GoogleFonts.poppins( + fontSize: 10, + color: color, + // color: const Color(0xFFEAF3FB), + fontWeight: FontWeight.w700, + ), + ), + ), + ], + ), + ); + } + + Widget statusCard(String label, int count) { + return Column( + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), + decoration: BoxDecoration( + color: const Color(0xFFEAF3FB), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + Text( + count.toString(), + style: GoogleFonts.poppins( + fontSize: 18, + color: Colors.black87, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 5), + Text( + label, + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black87, + ), + ), + ], + ), + ), + ], + ); + } + + Widget buildCategoryCard(String title, IconData icon, List statusLabels,List values) { + + final statusIcons = [ + Icons.calendar_today, + Icons.assignment, + Icons.verified, + Icons.block, + Icons.cancel, + ]; + + final statusColors = [ + Color(0xFFFBFFCA), + Color(0xFFFFF1CD),// Colors.yellow.shade100, // Color(0xFFCAE77B), + Color(0xFFDAFFE8),// Colors.green.shade100, // Color(0xFF72D480), + Color(0xFFFFD6D3),// Colors.red.shade100, // Color(0xFFF88C8C), + Color(0xFFFFA8A8), // Colors.red.shade200, // Color(0xFFE94B4B), + ]; + + final statusIconColors = [ + Color(0xFFB1BC1A), + Color(0xFFCC9300), + Color(0xFF509269), + Color(0xFFD25E55), + Color(0xFFAE0303), + ]; + + return Container( + padding: const EdgeInsets.all(16), + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(12), + // ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.blueGrey, + blurRadius: 5, + offset: Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: const BoxDecoration( + // color: Colors.blue, + color: Color(0xFF004A8E), + shape: BoxShape.circle, + ), + child: Icon( + icon, + color: Colors.white, + size: 20, + ), + ), + const SizedBox(width: 10), + Text(title, style: GoogleFonts.poppins( + color: Colors.black87, + fontWeight: FontWeight.bold + ),), + ], + ), + const SizedBox(height: 12), + ...List.generate(values.length, (index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + // Icon(statusIcons[index], size: 15, color: statusIconColors[index]), + Container( + width: 28, + height: 28, + decoration: BoxDecoration( + color: statusColors[index], // background color + borderRadius: BorderRadius.circular(4), // square with slight rounding + ), + alignment: Alignment.center, + child: Icon( + statusIcons[index], + size: 15, + color: statusIconColors[index], // icon color + ), + ), + const SizedBox(width: 6), + Text(statusLabels[index], style: GoogleFonts.poppins( + color: Colors.black87, + ),), + ], + ), + Text(values[index].toString(), style: GoogleFonts.poppins( + fontSize: 10, + color: Colors.black87, + fontWeight: FontWeight.bold, + ),), + ], + ), + ); + }), + ], + ), + ); + } + + // Widget buildCategoryCard(String title, IconData icon,statusLabels,statusvalue) { + // + // + // return Container( + // padding: const EdgeInsets.all(16), + // // decoration: BoxDecoration( + // // color: Colors.white, + // // borderRadius: BorderRadius.circular(12), + // // ), + // + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Row( + // children: [ + // Container( + // padding: const EdgeInsets.all(8), + // decoration: const BoxDecoration( + // color: Colors.blue, + // shape: BoxShape.circle, + // ), + // child: Icon( + // icon, + // color: Colors.white, + // size: 20, + // ), + // ), + // const SizedBox(width: 10), + // Text(title, style: GoogleFonts.poppins( + // color: Colors.black87, + // fontWeight: FontWeight.bold + // ),), + // ], + // ), + // const SizedBox(height: 12), + // ...List.generate(statusvalue.length, (index) { + // return Padding( + // padding: const EdgeInsets.symmetric(vertical: 10), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Row( + // children: [ + // // Icon(statusIcons[index], size: 20, color: statusColors[index]), + // Container( + // padding: const EdgeInsets.all(8), + // decoration: BoxDecoration( + // color: statusColors[index], // Background color behind the icon + // borderRadius: BorderRadius.circular(10), // Rounded square + // boxShadow: [ + // BoxShadow( + // color: Colors.grey, // Shadow color + // spreadRadius: 1, + // blurRadius: 5, + // offset: const Offset(0, 2), // Shadow position + // ), + // ], + // ), + // child: Icon( + // statusIcons[index], + // color: statusIconColors[index], + // size: 20, + // // color: statusColors[index], + // ), + // ), + // const SizedBox(width: 6), + // Text(statusLabels[index]), + // ], + // ), + // + // ], + // ), + // ); + // }), + // ], + // ), + // ); + // } return ResponsiveBuilder( builder: (context, sizingInfo) { @@ -322,94 +737,137 @@ class StatusDashboardState extends State { child: LayoutBuilder( builder: (context, constraints) { return SingleChildScrollView( - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight, - ), - child: IntrinsicHeight( - // Only needed if child layout depends on height - child: Container( - decoration: BoxDecoration( - color: - isDesktop - ? Colors.white - : const Color(0xFFFCFCFC), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.all(30.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, + // child: ConstrainedBox( + // constraints: BoxConstraints( + // minHeight: constraints.maxHeight, + // ), + // ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // First Row: Toggle Buttons Row + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + height: 36, + decoration: BoxDecoration( + color: const Color(0xFFEAEAEA), + borderRadius: BorderRadius.circular(20), + ), + child: Row( + children: [ + toggleChip("Today"), + toggleChip("This Week"), + ], + ), + ), + ], + ), + const SizedBox(height: 20), + + // Second Row: Domestic & International and Status + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // LEFT SIDE + Expanded( + flex: 2, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.blueGrey, + blurRadius: 5, + offset: Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(15), + child: Row( children: [ - Wrap( - spacing: 10, - runSpacing: 10, - children: - typeBasedCount.map((item) { - double cardWidth = - isDesktop - ? (MediaQuery.of( - context, - ).size.width * - 0.75 - - 10) / - 2 // 80% width padding adjusted - : MediaQuery.of( - context, - ).size.width - - 24; // full width with padding - - return SizedBox( - width: cardWidth, - child: buildInfoCard( - item['value'], - item['count'], - cardWidth, - ), - ); - }).toList(), - ), - const SizedBox(height: 20), - Wrap( - spacing: 10, - runSpacing: 10, - children: - statusBasedCount.map((item) { - double cardWidth = - isDesktop - ? (MediaQuery.of( - context, - ).size.width * - 0.90 - - 50) / - 6 // desktop layout: 6 cards per row - : MediaQuery.of( - context, - ).size.width - - 24; // mobile: full width - - return SizedBox( - width: cardWidth, - child: buildInfoCard( - item['value'], - item['count'], - cardWidth, - ), - ); - }).toList(), - ), + ...typeData.map((item) { + return Expanded( + child: Column( + children: [ + buildTopCard( + // icon: item['value'] == "Domestic" + // ? Icons.home + // : Icons.travel_explore, + color: item['value'] == "Domestic" + ? Color(0xFF0DB04B) + : Color(0xFF004A8E), + label: item['value'], + count: item['count'], + bgColor: item['value'] == "Domestic" + ? const Color(0xFFD6FBE4) + : const Color(0xFFD9E8FF), + ), + ], + ), + ); + }).toList(), ], ), + ), + ), + const SizedBox(width: 20), + // RIGHT SIDE + Expanded( + flex: 3, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.blueGrey, + blurRadius: 5, + offset: Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Status", + style: GoogleFonts.poppins( + fontSize: 19, + color: Colors.black87, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 23), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ...statusData.map((item) => statusCard(item['value'], item['count'])).toList(), + ], + ), + ], ), ), - ], - ), + ), + ], ), - ), + const SizedBox(height: 20), + + // Third Row: Flight, Accommodation, Forex + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: buildCategoryCard("Flight", Icons.flight,statusLabels,flightData)), + const SizedBox(width: 10), + Expanded(child: buildCategoryCard("Accomodation", Icons.hotel_outlined,statusLabels,accommodationData)), + const SizedBox(width: 10), + Expanded(child: buildCategoryCard("Forex", Icons.attach_money,statusLabels,forexData)), + ], + ), + ], ), ); }, diff --git a/lib/Screens/department/departmentDetails.dart b/lib/Screens/department/departmentDetails.dart index dbb9e7a..0f69ca3 100644 --- a/lib/Screens/department/departmentDetails.dart +++ b/lib/Screens/department/departmentDetails.dart @@ -50,6 +50,7 @@ class DepartmentDataState extends State { String? userId; int? departmentDataId; late String isActive = "1"; + bool isDisable = false; List dataHeader = ["dropdown_value", "description"]; @@ -163,9 +164,12 @@ class DepartmentDataState extends State { userId = await getUserId(); setState(() { + isDisable = true; // This triggers UI rebuild with error messages if (validateData()) { postDepartmentData(); + }else{ + isDisable = false; } }); @@ -222,11 +226,20 @@ class DepartmentDataState extends State { _clearError(); widget.fetchGetDepartment(); // dispose(); - Navigator.of(context).pop(); + if (context.mounted) { + Navigator.of(context).pop(); // Close modal only if mounted + } + setState(() { + isDisable = false; + }); } else if (response.statusCode == 404) { - Navigator.of(context).pop(); + if (context.mounted) { + Navigator.of(context).pop(); + } final message = jsonDecode(response.body)['message'] ?? 'Unknown error'; - + setState(() { + isDisable = false; + }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), @@ -237,9 +250,15 @@ class DepartmentDataState extends State { } else { print("Failed to submit. Status: ${response.statusCode}"); print("Error: ${response.body}"); + setState(() { + isDisable = false; + }); } } catch (e) { print(" Error submitting plan: $e"); + setState(() { + isDisable = false; + }); } } @@ -409,10 +428,21 @@ class DepartmentDataState extends State { // ), SizedBox( child: ElevatedButton( - onPressed: () { - handleSubmit(); + onPressed: isDisable + ? null + : () async { + setState(() { + isDisable = true; + }); + + await handleSubmit(); // You can get text from commentController.text // Navigator.of(context).pop(); // Close the modal + + // Optional: re-enable only on error + // setState(() { + // isDisable = false; + // }); }, style: ElevatedButton.styleFrom( backgroundColor: widget.layoutColor, diff --git a/lib/Screens/department/department_list.dart b/lib/Screens/department/department_list.dart index bf97295..215defd 100644 --- a/lib/Screens/department/department_list.dart +++ b/lib/Screens/department/department_list.dart @@ -132,6 +132,7 @@ class DepartmentListState extends State { } Future> fetchGetDepartment() async { + // return []; final String apiUrlData = '$apiUrl/api/getDepartmentList?for=table_view'; final String? token = await getToken(); @@ -284,7 +285,7 @@ class DepartmentListState extends State { isDesktop: isDesktop, breadcrumbItems: [ BreadcrumbItem( - title: 'Organization Settings', + title: 'Org Settings', tooltip: 'Go To Organization Settings', onTap: (context) { context.go("/OrganizationSettings"); @@ -454,6 +455,7 @@ class DepartmentListState extends State { FutureBuilder>( future: futureDepartment, builder: (context, snapshot) { + final adjHgt = MediaQuery.of(context).size.height; if (futureDepartment == null) { CircularProgressIndicator(); } @@ -479,9 +481,9 @@ class DepartmentListState extends State { // fontWeight: FontWeight.bold, // color: Colors.redAccent), // ), - const SizedBox(height: 8), + SizedBox(height: adjHgt / 4), Text( - "No Department Available ", + "No Data Found ", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, @@ -490,15 +492,15 @@ class DepartmentListState extends State { ), ), const SizedBox(height: 20), - Text( - "Please Create Department Details", - textAlign: TextAlign.center, - style: GoogleFonts.poppins( - fontSize: 16, - color: Colors.grey, - ), - ), - const SizedBox(height: 20), + // Text( + // "Please Create Department Details", + // textAlign: TextAlign.center, + // style: GoogleFonts.poppins( + // fontSize: 16, + // color: Colors.grey, + // ), + // ), + // const SizedBox(height: 20), ], ), ), @@ -905,7 +907,7 @@ class DepartmentListState extends State { filteredDepartment.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, @@ -920,7 +922,7 @@ class DepartmentListState extends State { filteredDepartment.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, diff --git a/lib/Screens/group/groupDetails.dart b/lib/Screens/group/groupDetails.dart index 215c08a..0107aaf 100644 --- a/lib/Screens/group/groupDetails.dart +++ b/lib/Screens/group/groupDetails.dart @@ -66,6 +66,7 @@ class GroupDataState extends State { int? groupDataId; late String isActive = "1"; + bool isDisable = false; List dataHeader = [ "name", @@ -227,9 +228,12 @@ class GroupDataState extends State { userId = await getUserId(); setState(() { + isDisable = true; // This triggers UI rebuild with error messages if (validateData()) { postGroupData(); + }else{ + isDisable = false; } }); @@ -280,11 +284,21 @@ class GroupDataState extends State { // _clearError(); _clearError(); await widget.fetchGetGroup(); + if (context.mounted) { + Navigator.of(context).pop(); // Close modal only if mounted + } + setState(() { + isDisable = false; + }); // dispose(); - Navigator.of(context).pop(); } else if (response.statusCode == 404) { - Navigator.of(context).pop(); + if (context.mounted) { + Navigator.of(context).pop(); + } + setState(() { + isDisable = false; + }); final message = jsonDecode(response.body)['message'] ?? 'Unknown error'; ScaffoldMessenger.of(context).showSnackBar( @@ -294,12 +308,33 @@ class GroupDataState extends State { behavior: SnackBarBehavior.floating, ), ); - } else { + } + else { print("Failed to submit plan. Status: ${response.statusCode}"); print("Error: ${response.body}"); + final message = jsonDecode(response.body); + final errorMessage = message['messages']?['error'] ?? 'Unknown error occurred'; + + if (errorMessage.contains("Duplicate entry")) { + _clearError(); + await widget.fetchGetGroup(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Group Already Exists!"), + backgroundColor: Colors.orange, + behavior: SnackBarBehavior.floating, + ), + ); + } + setState(() { + isDisable = false; + }); } } catch (e) { print(" Error submitting plan: $e"); + setState(() { + isDisable = false; + }); } } @@ -377,7 +412,6 @@ class GroupDataState extends State { CustomTextFieldForexWrapper( // isFocused: false, isFocused: focusStates["nameFocused"] ?? false, - isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( @@ -444,6 +478,7 @@ class GroupDataState extends State { SizedBox(height: 5), CustomTextFieldForexWrapper( isFocused: focusStates["domestic_policy_nameFocused"] ?? false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: widget.isDesktop, child: SizedBox( height: 40, @@ -498,7 +533,7 @@ class GroupDataState extends State { borderRadius: BorderRadius.circular(8), borderSide: BorderSide( color: - (focusStates["country_codeFocused"] ?? false) + (focusStates["domestic_policy_nameFocused"] ?? false) ? widget.layoutColor! : Colors.white, // width: 0.5, @@ -507,7 +542,7 @@ class GroupDataState extends State { enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: - (focusStates["country_codeFocused"] ?? false) + (focusStates["domestic_policy_nameFocused"] ?? false) ? widget.layoutColor! : Colors.white, // : const Color(0xFFD6D5E6), @@ -518,9 +553,8 @@ class GroupDataState extends State { focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: widget.layoutColor!, width: 1), ), - contentPadding: EdgeInsets.symmetric( - horizontal: 8, - ) + contentPadding: EdgeInsets.symmetric(horizontal: 10.0, + vertical: 8.0,), // contentPadding: EdgeInsets.symmetric(horizontal: 1), ), ), @@ -583,7 +617,7 @@ class GroupDataState extends State { CustomTextFieldForexWrapper( isFocused: focusStates["international_policy_nameFocused"] ?? false, - + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: widget.isDesktop, child: SizedBox( height: 40, @@ -639,20 +673,20 @@ class GroupDataState extends State { borderRadius: BorderRadius.circular(8), borderSide: BorderSide( color: - (focusStates["country_codeFocused"] ?? false) + (focusStates["international_policy_nameFocused"] ?? false) ? widget.layoutColor! : Colors.white, - // width: 0.5, + width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: - (focusStates["country_codeFocused"] ?? false) + (focusStates["international_policy_nameFocused"] ?? false) ? widget.layoutColor! : Colors.white, // : const Color(0xFFD6D5E6), - // width: 0.5, + width: 0.5, // const Color(0xFFD6D5E6), ), ), @@ -794,10 +828,25 @@ class GroupDataState extends State { // ), SizedBox( child: ElevatedButton( - onPressed: () { - handleSubmit(); + // onPressed: () { + // handleSubmit(); + // // You can get text from commentController.text + // // Navigator.of(context).pop(); // Close the modal + // }, + onPressed: isDisable + ? null + : () async { + setState(() { + isDisable = true; + }); + await handleSubmit(); // You can get text from commentController.text // Navigator.of(context).pop(); // Close the modal + + // Optional: re-enable only on error + // setState(() { + // isDisable = false; + // }); }, style: ElevatedButton.styleFrom( backgroundColor: widget.layoutColor, diff --git a/lib/Screens/group/groupList.dart b/lib/Screens/group/groupList.dart index 35be928..f67f303 100644 --- a/lib/Screens/group/groupList.dart +++ b/lib/Screens/group/groupList.dart @@ -117,6 +117,7 @@ class _GroupListState extends State { } Future> fetchGroups() async { + // return []; final result = await apiService.fetchAllGroup(); return result; // Returning raw JSON list } @@ -303,7 +304,7 @@ class _GroupListState extends State { isDesktop: isDesktop, breadcrumbItems: [ BreadcrumbItem( - title: 'Organization Settings', + title: 'Org Settings', tooltip: 'Go To Organization Settings', onTap: (context) { context.go("/OrganizationSettings"); @@ -475,6 +476,7 @@ class _GroupListState extends State { FutureBuilder>( future: futureGroups, builder: (context, snapshot) { + final adjHgt = MediaQuery.of(context).size.height; if (futureGroups == null) { return const CircularProgressIndicator(); } @@ -490,9 +492,9 @@ class _GroupListState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - const SizedBox(height: 8), + SizedBox(height: adjHgt / 4), Text( - "No Group Found", + "No Data Found", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, @@ -501,15 +503,15 @@ class _GroupListState extends State { ), ), const SizedBox(height: 20), - Text( - "Please Create Group", - textAlign: TextAlign.center, - style: GoogleFonts.poppins( - fontSize: 16, - color: Colors.grey, - ), - ), - const SizedBox(height: 20), + // Text( + // "Please Create Group", + // textAlign: TextAlign.center, + // style: GoogleFonts.poppins( + // fontSize: 16, + // color: Colors.grey, + // ), + // ), + // const SizedBox(height: 20), ], ), ), @@ -612,12 +614,27 @@ class _GroupListState extends State { return DataRow( cells: [ + // DataCell( + // Text( + // "${group['name'] ?? ''}", + // style: TextStyle( + // fontSize: 13, + // fontFamily: "Inter", + // ), + // ), + // ), DataCell( - Text( - "${group['name'] ?? ''}", - style: TextStyle( - fontSize: 13, - fontFamily: "Inter", + ConstrainedBox( + constraints: BoxConstraints(maxWidth: 200), // limit description width + child: Text( + "${group['name'] ?? ''}", + style: TextStyle( + fontSize: 13, + fontFamily: "Inter", + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, // optional: show only 1 line + softWrap: false, ), ), ), @@ -639,12 +656,27 @@ class _GroupListState extends State { ), ), ), + // DataCell( + // Text( + // "${group['description'] ?? 'N/A'}", + // style: TextStyle( + // fontSize: 13, + // fontFamily: "Inter", + // ), + // ), + // ), DataCell( - Text( - "${group['description'] ?? 'N/A'}", - style: TextStyle( - fontSize: 13, - fontFamily: "Inter", + ConstrainedBox( + constraints: BoxConstraints(maxWidth: 200), // limit description width + child: Text( + "${group['description'] ?? 'N/A'}", + style: TextStyle( + fontSize: 13, + fontFamily: "Inter", + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, ), ), ), @@ -984,7 +1016,7 @@ class _GroupListState extends State { filteredGroups.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, @@ -999,7 +1031,7 @@ class _GroupListState extends State { paginatedGroup.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, diff --git a/lib/Screens/hotels/hotelsDetails.dart b/lib/Screens/hotels/hotelsDetails.dart index feb40b1..e876093 100644 --- a/lib/Screens/hotels/hotelsDetails.dart +++ b/lib/Screens/hotels/hotelsDetails.dart @@ -54,6 +54,7 @@ class HotelsDataState extends State { String? userId; int? hotelsDataId; late String isActive = "1"; + bool isDisable = false; List dataHeader = [ "hotel_name", @@ -196,9 +197,12 @@ class HotelsDataState extends State { userId = await getUserId(); setState(() { + isDisable = true; // This triggers UI rebuild with error messages if (validateData()) { postHotelsData(); + }else{ + isDisable = false; } }); @@ -250,20 +254,24 @@ class HotelsDataState extends State { hotelsDataId != null ? await http.put(uri, headers: headers, body: body) : await http.post(uri, headers: headers, body: body); - if (response.statusCode == 200 || response.statusCode == 201) { print("Hotels Details Created successfully!"); print("Response: ${response.body}"); - // _clearError(); _clearError(); await widget.fetchGetHotels(); - // dispose(); - Navigator.of(context).pop(); + if (context.mounted) { + Navigator.of(context).pop(); // Close modal only if mounted + } + setState(() { + isDisable = false; + }); + // Do NOT re-enable here if success } else if (response.statusCode == 404) { - Navigator.of(context).pop(); + if (context.mounted) { + Navigator.of(context).pop(); + } final message = jsonDecode(response.body)['message'] ?? 'Unknown error'; - ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), @@ -271,13 +279,26 @@ class HotelsDataState extends State { behavior: SnackBarBehavior.floating, ), ); + setState(() { + isDisable = false; + }); + } else { print("Failed to submit plan. Status: ${response.statusCode}"); print("Error: ${response.body}"); + + setState(() { + isDisable = false; + }); } - } catch (e) { - print(" Error submitting plan: $e"); } + catch (e) { + print("Error submitting plan: $e"); + setState(() { + isDisable = false; + }); + } + } @override @@ -691,10 +712,21 @@ class HotelsDataState extends State { // ), SizedBox( child: ElevatedButton( - onPressed: () { - handleSubmit(); + onPressed: isDisable + ? null + : () async { + setState(() { + isDisable = true; + }); + + await handleSubmit(); // You can get text from commentController.text // Navigator.of(context).pop(); // Close the modal + + // Optional: re-enable only on error + // setState(() { + // isDisable = false; + // }); }, style: ElevatedButton.styleFrom( backgroundColor: widget.layoutColor, diff --git a/lib/Screens/hotels/hotels_list.dart b/lib/Screens/hotels/hotels_list.dart index 0838d5f..658e62d 100644 --- a/lib/Screens/hotels/hotels_list.dart +++ b/lib/Screens/hotels/hotels_list.dart @@ -135,6 +135,7 @@ class HotelsDataListState extends State { } Future> fetchGetHotels() async { + // return []; orgId = await getOrgId(); final String apiUrlData = '$apiUrl/api/getHotels?for=table_view'; @@ -335,7 +336,7 @@ class HotelsDataListState extends State { isDesktop: isDesktop, breadcrumbItems: [ BreadcrumbItem( - title: 'Organization Settings', + title: 'Org Settings', tooltip: 'Go To Organization Settings', onTap: (context) { context.go("/OrganizationSettings"); @@ -503,6 +504,7 @@ class HotelsDataListState extends State { FutureBuilder>( future: futureHotels, builder: (context, snapshot) { + final adjHgt = MediaQuery.of(context).size.height; if (futureHotels == null) { return CircularProgressIndicator(); } @@ -528,9 +530,9 @@ class HotelsDataListState extends State { // fontWeight: FontWeight.bold, // color: Colors.redAccent), // ), - const SizedBox(height: 8), + SizedBox(height: adjHgt / 4), Text( - "No Hotels Available ", + "No Data Found ", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, @@ -539,15 +541,15 @@ class HotelsDataListState extends State { ), ), const SizedBox(height: 20), - Text( - "Please Create Hotels", - textAlign: TextAlign.center, - style: GoogleFonts.poppins( - fontSize: 16, - color: Colors.grey, - ), - ), - const SizedBox(height: 20), + // Text( + // "Please Create Hotels", + // textAlign: TextAlign.center, + // style: GoogleFonts.poppins( + // fontSize: 16, + // color: Colors.grey, + // ), + // ), + // const SizedBox(height: 20), ], ), ), @@ -922,7 +924,7 @@ class HotelsDataListState extends State { filteredHotels.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, @@ -937,7 +939,7 @@ class HotelsDataListState extends State { filteredHotels.isEmpty ? Center( child: Text( - "No matches found", + "No Matches Found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, diff --git a/lib/Screens/itnerary/accomodations.dart b/lib/Screens/itnerary/accomodations.dart index b628dcf..e4560ca 100644 --- a/lib/Screens/itnerary/accomodations.dart +++ b/lib/Screens/itnerary/accomodations.dart @@ -5,6 +5,7 @@ import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; import '../../widgets/custom_confirmation_dialog.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; @@ -76,6 +77,8 @@ class _AccomodationScreenState extends State { bool _checkOutTimeFocus = false; bool _commentsFocus = false; + Color layoutColor = Colors.grey; + void _addFocusListener(FocusNode node, Function(bool) onFocusChange) { node.addListener(() { setState(() { @@ -100,6 +103,9 @@ class _AccomodationScreenState extends State { "created_by": widget.loginUser, "updated_by": widget.loginUser, }; + print(":("); + print(_checkInController.text); + print(_checkInTimeController.text); if (widget.selectedItem != null) { if (widget.selectedItem?["indx"] != null && @@ -120,7 +126,9 @@ class _AccomodationScreenState extends State { @override void initState() { super.initState(); - + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); _addFocusListener( _destinationFocusNode, (focus) => _destinationFocused = focus, @@ -129,6 +137,7 @@ class _AccomodationScreenState extends State { _hotelNameFocusNode, (focus) => _isHotelNameFocused = focus, ); + _addFocusListener( _CategoryFocusNode, (focus) => _CategoryFocused = focus); _addFocusListener(_checkInFocusNode, (focus) => _checkInFocus = focus); _addFocusListener( _checkInTimeFocusNode, @@ -160,6 +169,14 @@ class _AccomodationScreenState extends State { flightLastTripDateNotifier = ValueNotifier(null); flightFirstToDestinationNotifier = ValueNotifier(null); + // // ✅ Check and set default times if empty + // if (_checkInTimeController.text.isEmpty) { + // _checkInTimeController.text = '14:00'; // 2 PM + // } + // if (_checkOutTimeController.text.isEmpty) { + // _checkOutTimeController.text = '12:00'; // 12 PM + // } + WidgetsBinding.instance.addPostFrameCallback((_) { loadCountryList(); @@ -176,12 +193,23 @@ class _AccomodationScreenState extends State { widget.selectedItem?["destination_city"] ?? result['firstToDestination']; + // if (checkinDate != null) { + // flightFirstTripDateNotifier.value = checkinDate; + // } + // + // if (checkoutDate != null) { + // flightLastTripDateNotifier.value = checkoutDate; + // } + + final tripType = result['tripType'] ; + if (checkinDate != null) { flightFirstTripDateNotifier.value = checkinDate; - } - - if (checkoutDate != null) { - flightLastTripDateNotifier.value = checkoutDate; + if (tripType == "Oneway") { + flightLastTripDateNotifier.value = checkinDate; + } else { + flightLastTripDateNotifier.value = checkoutDate ?? checkinDate; + } } if (destinationCity != null) { @@ -199,24 +227,25 @@ class _AccomodationScreenState 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) { - _checkInController.text = DateFormat('dd-MM-yyyy').format(parsedDate); + final checkInDateInput = flightFirstTripDateNotifier.value; + if (checkInDateInput != null && checkInDateInput.isNotEmpty) { + try { + final parsedDate = DateFormat("dd-MM-yyyy").parseStrict(checkInDateInput); + _checkInController.text = DateFormat("dd-MM-yyyy").format(parsedDate); + } catch (e) { + _checkInController.text = ''; + } } // final parsedEndDate = DateTime.tryParse(flightLastTripDateNotifier.value ?? ''); - final parsedEndDate = DateFormat( - "dd-MM-yyyy", - ).parse(flightLastTripDateNotifier.value ?? ''); - - if (parsedEndDate != null) { - // _checkOutController.text = DateFormat('dd-MM-yyyy').format(parsedEndDate); - - _checkOutController.text = DateFormat( - 'dd-MM-yyyy', - ).format(parsedEndDate); + final checkOutDateInput = flightLastTripDateNotifier.value; + if (checkOutDateInput != null && checkOutDateInput.isNotEmpty) { + try { + final parsedDate = DateFormat("dd-MM-yyyy").parseStrict(checkOutDateInput); + _checkOutController.text = DateFormat("dd-MM-yyyy").format(parsedDate); + } catch (e) { + _checkOutController.text = ''; + } } // ✅ Check and set default times if empty @@ -239,6 +268,24 @@ class _AccomodationScreenState extends State { } } + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + // setState(() { + // layoutColor = + // layoutString != null + // ? Color(int.parse(layoutString)) + // : Colors.redAccent; + // }); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + @override void dispose() { _destinationFocusNode.dispose(); @@ -272,8 +319,13 @@ class _AccomodationScreenState extends State { Map getFlightTripDateRange( List> flightData, ) { - print("FlightDAta - ${widget.flightData}"); - + String tt = ""; + if (widget.flightData.isNotEmpty) { + print("Trip Type - ${widget.flightData[0]['trip_type']}"); + tt = widget.flightData[0]['trip_type']; + } else { + print("No flight data available"); + } final allTrips = flightData .expand((flight) => flight['trips'] ?? []) @@ -298,6 +350,7 @@ class _AccomodationScreenState extends State { print("res1 - ${firstTrip['date']},"); print("res11 - $firstTripDate"); + print("res22 - $tt"); // Use `List.where` instead of `firstWhere` so you can handle an empty result @@ -319,6 +372,7 @@ class _AccomodationScreenState extends State { // 'lastTripDate': nextTrip['date'], // 'lastTripDate': lastTrip['date'], 'firstToDestination': firstTripToDestination['to_place'], + 'tripType': tt, // trip_type: Oneway }; } @@ -503,6 +557,8 @@ class _AccomodationScreenState extends State { List _buildFirstRow(isDesktop) { List purposeList = widget.apiDataForClass?['hotel_class'] ?? []; + print("hotel_classhotel_class"); + print(purposeList); List> dropdownItems = purposeList @@ -655,6 +711,20 @@ class _AccomodationScreenState extends State { child: SizedBox( height: 40, width: double.infinity, + child: Focus( + focusNode: _CategoryFocusNode, + + onFocusChange: (hasFocus) { + setState(() { + _CategoryFocused = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + _CategoryFocusNode?.requestFocus(); + }, child: DropdownSearch>( key: selectedClass == null @@ -697,10 +767,34 @@ class _AccomodationScreenState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_CategoryFocused ?? false) + ? layoutColor! + : Colors.white, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_CategoryFocused ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 1, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 1), + ), + contentPadding: const EdgeInsets.symmetric( horizontal: 10, vertical: 10, ), @@ -764,7 +858,7 @@ class _AccomodationScreenState extends State { } } : null, - ), + ),),), ), ), if (errorMessages["class"] != null) ...[ diff --git a/lib/Screens/itnerary/bus.dart b/lib/Screens/itnerary/bus.dart index faadf5e..9522e4f 100644 --- a/lib/Screens/itnerary/bus.dart +++ b/lib/Screens/itnerary/bus.dart @@ -113,7 +113,7 @@ class _BusScreenState extends State { }); _dateFocusNode.addListener(() { setState(() { - _dateFocus = _fromFocusNode.hasFocus; + _dateFocus = _dateFocusNode.hasFocus; }); }); @@ -144,6 +144,9 @@ class _BusScreenState extends State { @override void dispose() { _tripTypeFocusNode.dispose(); + _dateFocusNode.dispose(); + _timeFocusNode.dispose(); + _tripTypeController.dispose(); _hotelNameController.dispose(); _fromController.dispose(); @@ -536,7 +539,11 @@ class _BusScreenState extends State { child: SizedBox( height: 40, child: GestureDetector( - onTap: () => _selectCheckOutDate(context), + // onTap: () => _selectCheckOutDate(context), + onTap: () { + _dateFocusNode.requestFocus(); + _selectCheckOutDate(context); + }, child: AbsorbPointer( child: TextField( focusNode: _dateFocusNode, @@ -588,6 +595,7 @@ class _BusScreenState extends State { onTap: () { // _selectedCheckOutTime = null; // ✅ Reset time variable _timeController.text = ""; // ✅ Clear text field + _timeFocusNode.requestFocus(); _selectCheckOutTime(context); }, child: AbsorbPointer( diff --git a/lib/Screens/itnerary/forex.dart b/lib/Screens/itnerary/forex.dart index a27f3f6..b8f619e 100644 --- a/lib/Screens/itnerary/forex.dart +++ b/lib/Screens/itnerary/forex.dart @@ -279,7 +279,7 @@ class _ForexScreenState extends State { if (cardNumber.length < 15) { // Show error or return false print("Card number must be 15 digits"); - errorMessages["card_number"] = "Card number must be atleat 15 digits"; + errorMessages["card_number"] = "Card number must be atleast 15 digits"; } } @@ -1091,8 +1091,8 @@ class _ForexScreenState extends State { // // }, onTap: () async { + focusNodes["_forexStartDate"]?.requestFocus(); await _selectCheckOutDate(context); - if (textControllers["_forexEndDate"]!.text.isNotEmpty) { DateTime? startDate = _parseDate( textControllers["_forexStartDate"]!.text, @@ -1189,6 +1189,7 @@ class _ForexScreenState extends State { child: GestureDetector( // onTap: () => _selectForexEndDate(context), onTap: () async { + focusNodes["_forexEndDate"]?.requestFocus(); await _selectForexEndDate(context); if (textControllers["_forexEndDate"]!.text.isNotEmpty) { diff --git a/lib/Screens/itnerary/miscellaneous.dart b/lib/Screens/itnerary/miscellaneous.dart index 201fb0d..745383f 100644 --- a/lib/Screens/itnerary/miscellaneous.dart +++ b/lib/Screens/itnerary/miscellaneous.dart @@ -4,6 +4,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; +import '../../utils/auth_utils.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; @@ -44,10 +45,10 @@ class _MiscellaneousScreenState extends State { late TextEditingController _commentsController = TextEditingController(); - bool _isHotelNameFocused = false; + bool _hotelNameFocused = false; bool _commentsFocus = false; String? selectedSpecialType; - + Color layoutColor = Colors.grey; Map errorMessages = {}; Map get miscellaneousData { @@ -77,10 +78,12 @@ class _MiscellaneousScreenState extends State { if (widget.selectedItem == null) { _commentsController.clear(); } - + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); _hotelNameFocusNode.addListener(() { setState(() { - _isHotelNameFocused = _hotelNameFocusNode.hasFocus; + _hotelNameFocused = _hotelNameFocusNode.hasFocus; }); }); @@ -104,11 +107,30 @@ class _MiscellaneousScreenState extends State { @override void dispose() { _tripTypeFocusNode.dispose(); + _hotelNameFocusNode.dispose(); _tripTypeController.dispose(); _commentsController.dispose(); super.dispose(); } + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + // setState(() { + // layoutColor = + // layoutString != null + // ? Color(int.parse(layoutString)) + // : Colors.redAccent; + // }); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + bool isValidData(Map data) { errorMessages.clear(); // Reset errors @@ -281,8 +303,9 @@ class _MiscellaneousScreenState extends State { // ), // ), CustomTextFieldItnerarySubWrapper( - isFocused: _isHotelNameFocused, + isFocused: _hotelNameFocused, isDesktop: isDesktop, + padding: const EdgeInsets.symmetric(horizontal: 0), width: isDesktop ? MediaQuery.of(context).size.width * 0.34 @@ -290,6 +313,19 @@ class _MiscellaneousScreenState extends State { child: SizedBox( height: 40, width: double.infinity, + child: Focus( + focusNode: _hotelNameFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _hotelNameFocused = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + _hotelNameFocusNode?.requestFocus(); + }, child: DropdownSearch>( // focusNode: _taxiReqFocusNode, items: purposeList.cast>(), @@ -318,9 +354,33 @@ class _MiscellaneousScreenState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(4), + borderSide: BorderSide( + color: + (_hotelNameFocused ?? false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_hotelNameFocused ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 0.5), + ), contentPadding: EdgeInsets.symmetric( horizontal: 10, vertical: 10, @@ -348,7 +408,7 @@ class _MiscellaneousScreenState extends State { print("Updating form data: -> ${newValue ?? ""}"); } : null, - ), + ),),) ), ), if (errorMessages["special_request"] != null) ...[ diff --git a/lib/Screens/itnerary/taxi.dart b/lib/Screens/itnerary/taxi.dart index c26516a..3a2b12f 100644 --- a/lib/Screens/itnerary/taxi.dart +++ b/lib/Screens/itnerary/taxi.dart @@ -5,6 +5,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; +import '../../utils/auth_utils.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; @@ -41,6 +42,7 @@ class _TaxiScreenState extends State { final FocusNode _timeFocusNode = FocusNode(); final FocusNode _numPassengerFocusNode = FocusNode(); final FocusNode _commentsFocusNode = FocusNode(); + final FocusNode _carTypeFocusNode = FocusNode(); late TextEditingController _destinationController = TextEditingController(); late TextEditingController _locationController = TextEditingController(); @@ -54,12 +56,14 @@ class _TaxiScreenState extends State { bool _toFocus = false; bool _dateFocus = false; bool _taxiReqFocused = false; + bool _carTypeFocused = false; bool _numPassengerFocus = false; bool _timeFocus = false; bool _commentsFocus = false; String? selectedReqTaxi; String? selectedCarType; + Color layoutColor = Colors.grey; Map get taxiData { Map data = { @@ -98,6 +102,10 @@ class _TaxiScreenState extends State { void initState() { super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + _addFocusListener( _destinationFocusNode, (focus) => _destinationFocus = focus, @@ -106,6 +114,7 @@ class _TaxiScreenState extends State { _addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus); _addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus); _addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus); + _addFocusListener(_carTypeFocusNode, (focus) => _carTypeFocused = focus); _addFocusListener( _numPassengerFocusNode, (focus) => _numPassengerFocus = focus, @@ -146,10 +155,22 @@ class _TaxiScreenState extends State { }); } + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + @override void dispose() { _destinationFocusNode.dispose(); _locationFocusNode.dispose(); + _carTypeFocusNode.dispose(); _destinationController.dispose(); _dateController.dispose(); _timeController.dispose(); @@ -397,9 +418,22 @@ class _TaxiScreenState extends State { CustomTextFieldItnerarySubWrapper( isFocused: _toFocus, isDesktop: isDesktop, + padding: const EdgeInsets.symmetric(horizontal: 0), child: SizedBox( height: 40, width: double.infinity, + child: Focus( + focusNode: _carTypeFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _carTypeFocused = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + _carTypeFocusNode?.requestFocus(); + }, child: DropdownSearch>( // focusNode: _taxiReqFocusNode, items: purposeList.cast>(), @@ -428,9 +462,33 @@ class _TaxiScreenState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_carTypeFocused ?? false) + ? layoutColor! + : Colors.white, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_carTypeFocused ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 1, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 1), + ), contentPadding: EdgeInsets.symmetric( horizontal: 10, vertical: 10, @@ -464,7 +522,7 @@ class _TaxiScreenState extends State { print("Updating form data: -> ${newValue ?? ""}"); } : null, - ), + ),),), ), ), ], @@ -541,6 +599,7 @@ class _TaxiScreenState extends State { CustomTextFieldItnerarySubWrapper( isFocused: _taxiReqFocused, isDesktop: isDesktop, + padding: const EdgeInsets.symmetric(horizontal: 0), width: isDesktop ? MediaQuery.of(context).size.width * 0.34 @@ -548,6 +607,17 @@ class _TaxiScreenState extends State { child: SizedBox( height: 40, width: double.infinity, + child: Focus( + focusNode: _taxiReqFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _taxiReqFocused = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + _taxiReqFocusNode?.requestFocus(); + }, child: DropdownSearch>( // focusNode: _taxiReqFocusNode, items: purposeList.cast>(), @@ -576,12 +646,36 @@ class _TaxiScreenState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_taxiReqFocused ?? false) + ? layoutColor! + : Colors.white, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_taxiReqFocused ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 1, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 1), + ), contentPadding: EdgeInsets.symmetric( horizontal: 10, - vertical: 10, + vertical: 1, ), ), ), @@ -606,7 +700,7 @@ class _TaxiScreenState extends State { print("Updating form data: -> ${newValue ?? ""}"); } : null, - ), + ),),), ), ), ]; @@ -817,7 +911,11 @@ class _TaxiScreenState extends State { child: SizedBox( height: 40, child: GestureDetector( - onTap: () => _selectCheckOutDate(context), + // onTap: () => _selectCheckOutDate(context), + onTap: () { + _dateFocusNode.requestFocus(); + _selectCheckOutDate(context); + }, child: AbsorbPointer( child: TextField( focusNode: _dateFocusNode, @@ -868,6 +966,7 @@ class _TaxiScreenState extends State { child: GestureDetector( onTap: () { _timeController.text = ""; + _timeFocusNode.requestFocus(); _selectCheckOutTime(context); }, child: AbsorbPointer( diff --git a/lib/Screens/itnerary/train.dart b/lib/Screens/itnerary/train.dart index 2b3e806..446eabf 100644 --- a/lib/Screens/itnerary/train.dart +++ b/lib/Screens/itnerary/train.dart @@ -5,6 +5,7 @@ import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; import '../../widgets/custom_confirmation_dialog.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; @@ -44,7 +45,7 @@ class _TrainScreenState extends State { Map selectedValues = {}; final FocusNode _trainNoFocusNode = FocusNode(); - final FocusNode _hotelNameFocusNode = FocusNode(); + final FocusNode _typeOfClassFocusNode = FocusNode(); final FocusNode _fromFocusNode = FocusNode(); final FocusNode _toFocusNode = FocusNode(); final FocusNode _dateFocusNode = FocusNode(); @@ -60,7 +61,7 @@ class _TrainScreenState extends State { late TextEditingController _trainCommentsController = TextEditingController(); bool _trainNoFocused = false; - bool _isHotelNameFocused = false; + bool _typeOfClassFocus = false; bool _fromFocus = false; bool _toFocus = false; bool _dateFocus = false; @@ -71,6 +72,7 @@ class _TrainScreenState extends State { String? exceptionalClass = "0"; String? selectedFrom; String? selectedTo; + Color layoutColor = Colors.grey; Map errorMessages = {}; @@ -110,15 +112,17 @@ class _TrainScreenState extends State { @override void initState() { super.initState(); - + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); _trainNoFocusNode.addListener(() { setState(() { _trainNoFocused = _trainNoFocusNode.hasFocus; }); }); - _hotelNameFocusNode.addListener(() { + _typeOfClassFocusNode.addListener(() { setState(() { - _isHotelNameFocused = _hotelNameFocusNode.hasFocus; + _typeOfClassFocus = _typeOfClassFocusNode.hasFocus; }); }); _fromFocusNode.addListener(() { @@ -133,7 +137,7 @@ class _TrainScreenState extends State { }); _dateFocusNode.addListener(() { setState(() { - _dateFocus = _fromFocusNode.hasFocus; + _dateFocus = _dateFocusNode.hasFocus; }); }); _timeFocusNode.addListener(() { @@ -213,6 +217,13 @@ class _TrainScreenState extends State { @override void dispose() { _trainNoFocusNode.dispose(); + _dateFocusNode.dispose(); + _timeFocusNode.dispose(); + _typeOfClassFocusNode.dispose(); + _fromFocusNode.dispose(); + _toFocusNode.dispose(); + _commentsFocusNode.dispose(); + _trainNoController.dispose(); _hotelNameController.dispose(); _fromController.dispose(); @@ -223,6 +234,17 @@ class _TrainScreenState extends State { super.dispose(); } + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + void _clearError(String field) { if (mounted && errorMessages.containsKey(field)) { setState(() { @@ -632,12 +654,24 @@ class _TrainScreenState extends State { // ), // ), CustomTextFieldWrapper( - isFocused: _isHotelNameFocused, + isFocused: _typeOfClassFocus, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, child: SizedBox( height: 40, width: double.infinity, + child: Focus( + focusNode: _typeOfClassFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _typeOfClassFocus = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + _typeOfClassFocusNode?.requestFocus(); + }, child: DropdownSearch>( key: selectedClass == null @@ -678,9 +712,33 @@ class _TrainScreenState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_typeOfClassFocus ?? false) + ? layoutColor! + : Colors.white, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_typeOfClassFocus ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 1, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 1), + ), contentPadding: EdgeInsets.symmetric( horizontal: 10, vertical: 10, @@ -759,7 +817,7 @@ class _TrainScreenState extends State { }); } : null, - ), + ),),) ), ), if (errorMessages["class"] != null) ...[ @@ -874,15 +932,27 @@ class _TrainScreenState extends State { // ), CustomTextFieldItnerarySubWrapper( isFocused: _fromFocus ?? false, + padding: const EdgeInsets.symmetric(horizontal: 0), isDesktop: isDesktop, child: SizedBox( height: 40, + child: Focus( + focusNode: _fromFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _fromFocus = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + _fromFocusNode?.requestFocus(); + }, child: DropdownSearch( selectedItem: countryMap[selectedFrom], popupProps: PopupProps.menu( showSearchBox: true, fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), + constraints: BoxConstraints(maxHeight: 150),// maxHeight: 250 menuProps: const MenuProps(backgroundColor: Colors.white), itemBuilder: (context, item, isSelected) => Container( @@ -906,8 +976,32 @@ class _TrainScreenState extends State { items: countryMap.values.toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_fromFocus ?? false) + ? layoutColor! + : Colors.white, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_fromFocus ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 1, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 1), + ), + contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), dropdownBuilder: @@ -929,7 +1023,7 @@ class _TrainScreenState extends State { .key; }); }, - ), + ),),) ), ), if (errorMessages["from_station"] != null) ...[ @@ -1008,14 +1102,26 @@ class _TrainScreenState extends State { CustomTextFieldItnerarySubWrapper( isFocused: _toFocus ?? false, isDesktop: isDesktop, + padding: const EdgeInsets.symmetric(horizontal: 0), child: SizedBox( height: 40, + child: Focus( + focusNode: _toFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _toFocus = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + _toFocusNode?.requestFocus(); + }, child: DropdownSearch( selectedItem: countryMap[selectedTo], popupProps: PopupProps.menu( showSearchBox: true, fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), + constraints: BoxConstraints(maxHeight: 150), menuProps: const MenuProps(backgroundColor: Colors.white), itemBuilder: (context, item, isSelected) => Container( @@ -1039,8 +1145,32 @@ class _TrainScreenState extends State { items: countryMap.values.toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_toFocus ?? false) + ? layoutColor! + : Colors.white, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_toFocus ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 1, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 1), + ), + contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), dropdownBuilder: @@ -1062,7 +1192,7 @@ class _TrainScreenState extends State { .key; }); }, - ), + ),),), ), ), if (errorMessages["to_station"] != null) ...[ @@ -1094,7 +1224,11 @@ class _TrainScreenState extends State { child: SizedBox( height: 40, child: GestureDetector( - onTap: () => _selectCheckOutDate(context), + // onTap: () => _selectCheckOutDate(context), + onTap: () { + _dateFocusNode.requestFocus(); + _selectCheckOutDate(context); + }, child: AbsorbPointer( child: TextField( focusNode: _dateFocusNode, @@ -1146,6 +1280,7 @@ class _TrainScreenState extends State { child: GestureDetector( onTap: () { _timeController.text = ""; + _timeFocusNode.requestFocus(); _selectCheckOutTime(context); }, child: AbsorbPointer( diff --git a/lib/Screens/itnerary/visa.dart b/lib/Screens/itnerary/visa.dart index 2a660ec..6ca8052 100644 --- a/lib/Screens/itnerary/visa.dart +++ b/lib/Screens/itnerary/visa.dart @@ -5,6 +5,7 @@ import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_text_itnerary_sub.dart'; @@ -49,6 +50,7 @@ class _VisaScreenState extends State { List countryList = []; final FocusNode _tripTypeFocusNode = FocusNode(); + final FocusNode _countryFocusNode = FocusNode(); final FocusNode _hotelNameFocusNode = FocusNode(); final FocusNode _dateFocusNode = FocusNode(); final FocusNode _commentsFocusNode = FocusNode(); @@ -62,12 +64,14 @@ class _VisaScreenState extends State { late TextEditingController _visaCommentsController = TextEditingController(); bool _tripTypeFocused = false; + bool _countryFocused = false; bool _isHotelNameFocused = false; bool _dateFocus = false; bool _commentsFocus = false; String? selectedPurpose; String? selectedCountry; + Color layoutColor = Colors.grey; Map errorMessages = {}; @@ -97,8 +101,11 @@ class _VisaScreenState extends State { @override void initState() { super.initState(); - + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); _addFocusListener(_tripTypeFocusNode, (focus) => _tripTypeFocused = focus); + _addFocusListener(_countryFocusNode, (focus) => _countryFocused = focus); _addFocusListener( _hotelNameFocusNode, (focus) => _isHotelNameFocused = focus, @@ -144,6 +151,24 @@ class _VisaScreenState extends State { }); } + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + + // setState(() { + // layoutColor = + // layoutString != null + // ? Color(int.parse(layoutString)) + // : Colors.redAccent; + // }); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + }); + } + void _addFocusListener(FocusNode node, Function(bool) updateState) { node.addListener(() { setState(() { @@ -217,6 +242,7 @@ class _VisaScreenState extends State { @override void dispose() { _tripTypeFocusNode.dispose(); + _countryFocusNode.dispose(); _tripTypeController.dispose(); _hotelNameController.dispose(); _fromController.dispose(); @@ -519,12 +545,27 @@ class _VisaScreenState extends State { CustomTextFieldItnerarySubWrapper( isFocused: _isHotelNameFocused, isDesktop: isDesktop, + padding: const EdgeInsets.symmetric(horizontal: 0), width: isDesktop ? MediaQuery.of(context).size.width * 0.34 : MediaQuery.of(context).size.width * 0.66, child: SizedBox( height: 40, + child: Focus( + focusNode: _countryFocusNode, + + onFocusChange: (hasFocus) { + setState(() { + _countryFocused = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + _countryFocusNode?.requestFocus(); + }, child: DropdownSearch( selectedItem: countryMap[selectedCountry], popupProps: PopupProps.menu( @@ -575,8 +616,32 @@ class _VisaScreenState extends State { items: countryMap.values.toList(), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_countryFocused ?? false) + ? layoutColor! + : Colors.white, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_countryFocused ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 1, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 1), + ), + contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), dropdownBuilder: @@ -598,7 +663,7 @@ class _VisaScreenState extends State { .key; }); }, - ), + ),),), ), ), if (errorMessages["country_code"] != null) ...[ @@ -659,10 +724,24 @@ class _VisaScreenState extends State { CustomTextFieldWrapper( isFocused: _tripTypeFocused, isDesktop: isDesktop, + padding: const EdgeInsets.symmetric(horizontal: 0), width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, child: SizedBox( height: 40, width: double.infinity, + child: Focus( + focusNode: _tripTypeFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _tripTypeFocused = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + _tripTypeFocusNode?.requestFocus(); + }, child: DropdownSearch>( items: purposeList.cast>(), selectedItem: purposeList.firstWhere( @@ -690,9 +769,33 @@ class _VisaScreenState extends State { ); }, ), - dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_tripTypeFocused ?? false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_tripTypeFocused ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: layoutColor, width: 0.5), + ), contentPadding: EdgeInsets.symmetric( horizontal: 10, vertical: 10, @@ -734,7 +837,7 @@ class _VisaScreenState extends State { }); } : null, - ), + ),),), ), ), if (errorMessages["type_of_visa"] != null) ...[ @@ -764,6 +867,7 @@ class _VisaScreenState extends State { height: 40, child: GestureDetector( onTap: () async { + _dateFocusNode.requestFocus(); await _selectCheckOutDate(context); if (_dateController.text.isNotEmpty) { setState(() { diff --git a/lib/Screens/myTemplates/template.dart b/lib/Screens/myTemplates/template.dart index b1eb202..6a0a5ec 100644 --- a/lib/Screens/myTemplates/template.dart +++ b/lib/Screens/myTemplates/template.dart @@ -34,6 +34,7 @@ import '../../routes/custom_drawer.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../widgets/custom_breadcrumb_navigation.dart'; +import '../../widgets/custom_user_form.dart'; import '../../widgets/custom_user_travel.dart'; import 'dialog_placeholders.dart'; @@ -63,6 +64,8 @@ class TemplateState extends State