From 1b6188c584ffedea44e411f310957e18341cbc7f Mon Sep 17 00:00:00 2001 From: venbaittech Date: Wed, 30 Jul 2025 12:33:02 +0530 Subject: [PATCH] UI_USR_MNGMT_APPROVER --- lib/Screens/dashboard/status_dashboard.dart | 708 ++- lib/Screens/itnerary/flights.dart | 4466 +++++++++-------- .../itnerary_list/accomodation_list.dart | 630 ++- lib/Screens/itnerary_list/flight_list.dart | 387 +- lib/Screens/itnerary_list/forex_list.dart | 846 ++-- .../plans/dynamic_itinerary_stepper.dart | 2 +- .../create_user/create_user.dart | 20 +- .../create_user/office_details.dart | 1677 ++++--- lib/config/apiUrl.dart | 4 +- 9 files changed, 4688 insertions(+), 4052 deletions(-) diff --git a/lib/Screens/dashboard/status_dashboard.dart b/lib/Screens/dashboard/status_dashboard.dart index 1693f78..6d92983 100644 --- a/lib/Screens/dashboard/status_dashboard.dart +++ b/lib/Screens/dashboard/status_dashboard.dart @@ -52,14 +52,14 @@ class StatusDashboardState extends State { "Partially Approved", "Approved", "Rejected", - "Cancelled" + "Cancelled", ]; - // Extract counts for "Both" section - List getStatusValues(Map serviceData) { - final both = serviceData['Both'] ?? {}; - return statusLabels.map((label) => (both[label] ?? 0) as int).toList(); - } + // 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() { @@ -150,8 +150,7 @@ class StatusDashboardState extends State { checkbackbutton(); }); setState(() { - isLoading = true; - + isLoading = true; }); // If token exists, load the dashboard data loadDashboardData(); @@ -320,25 +319,27 @@ class StatusDashboardState extends State { setState(() { // currentData = selectedView == "Today" ? todayBasedCount : weekBasedCount; - typeData = selectedView == "Today" - ? typeBasedTodayCount - : typeBasedWeeklyCount ; - statusData = selectedView == "Today" - ? statusBasedTodayCount - : statusBasedWeeklyCount ; + 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'] ?? {}); + 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 @@ -403,6 +404,7 @@ class StatusDashboardState extends State { print("dashboard .."); } } + String capitalize(String s) => s[0].toUpperCase() + s.substring(1); Widget toggleChip(String label) { @@ -450,7 +452,7 @@ class StatusDashboardState extends State { child: Column( children: [ Tooltip( - message: label , + message: label, child: Image.asset( label == 'Domestic' ? 'assets/images/IconsImg/Domestic_new.png' @@ -501,7 +503,8 @@ class StatusDashboardState extends State { borderRadius: BorderRadius.circular(8), ), child: Column( - mainAxisAlignment: MainAxisAlignment.center, // vertically center everything + mainAxisAlignment: + MainAxisAlignment.center, // vertically center everything children: [ Text( count.toString(), @@ -529,8 +532,40 @@ class StatusDashboardState extends State { ); } - Widget buildCategoryCard(String title, IconData icon, List statusLabels,List values) { + Widget statusCardContainer(bool isDesktop, List cards) { + return isDesktop + ? Row( + mainAxisAlignment: MainAxisAlignment.start, + children: + cards + .map( + (card) => Padding( + padding: const EdgeInsets.only(right: 12.0), + child: card, + ), + ) + .toList(), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: + cards + .map( + (card) => Padding( + padding: const EdgeInsets.only(bottom: 12.0), + child: card, + ), + ) + .toList(), + ); + } + Widget buildCategoryCard( + String title, + IconData icon, + List statusLabels, + List values, + ) { final statusIcons = [ Icons.calendar_today, Icons.assignment, @@ -541,9 +576,9 @@ class StatusDashboardState extends State { 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(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), ]; @@ -584,17 +619,16 @@ class StatusDashboardState extends State { color: Color(0xFF004A8E), shape: BoxShape.circle, ), - child: Icon( - icon, - color: Colors.white, - size: 20, - ), + child: Icon(icon, color: Colors.white, size: 20), ), const SizedBox(width: 10), - Text(title, style: GoogleFonts.poppins( + Text( + title, + style: GoogleFonts.poppins( color: Colors.black87, - fontWeight: FontWeight.bold - ),), + fontWeight: FontWeight.bold, + ), + ), ], ), const SizedBox(height: 12), @@ -612,7 +646,9 @@ class StatusDashboardState extends State { height: 28, decoration: BoxDecoration( color: statusColors[index], // background color - borderRadius: BorderRadius.circular(4), // square with slight rounding + borderRadius: BorderRadius.circular( + 4, + ), // square with slight rounding ), alignment: Alignment.center, child: Icon( @@ -622,16 +658,20 @@ class StatusDashboardState extends State { ), ), const SizedBox(width: 6), - Text(statusLabels[index], style: GoogleFonts.poppins( - color: Colors.black87, - ),), + Text( + statusLabels[index], + style: GoogleFonts.poppins(color: Colors.black87), + ), ], ), - Text(values[index].toString(), style: GoogleFonts.poppins( - fontSize: 10, - color: Colors.black87, - fontWeight: FontWeight.bold, - ),), + Text( + values[index].toString(), + style: GoogleFonts.poppins( + fontSize: 10, + color: Colors.black87, + fontWeight: FontWeight.bold, + ), + ), ], ), ); @@ -736,251 +776,383 @@ class StatusDashboardState extends State { appBar: CustomAppBar(isDesktop: isDesktop), drawer: CustomDrawer(isDesktop: false), body: Padding( - padding: isDesktop - ? const EdgeInsets.symmetric(vertical: 5) - : EdgeInsets.zero, + padding: + isDesktop + ? const EdgeInsets.symmetric(vertical: 5) + : EdgeInsets.zero, child: Center( child: ConstrainedBox( - constraints: BoxConstraints( - maxWidth: 1200, - ), + constraints: BoxConstraints(maxWidth: 1200), child: SingleChildScrollView( child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15.0), // ✅ Scroll content padding + padding: const EdgeInsets.symmetric( + horizontal: 15.0, + ), // ✅ Scroll content padding child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - isLoading ? Center(child: CircularProgressIndicator()) : - LayoutBuilder( - builder: (context, constraints) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // First Row: Toggle Buttons Row - Row( - mainAxisAlignment: MainAxisAlignment.end, + isLoading + ? Center(child: CircularProgressIndicator()) + : LayoutBuilder( + builder: (context, constraints) { + return Column( + crossAxisAlignment: + CrossAxisAlignment.start, 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 - isDesktop - ? Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - 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), - ), - ], + // First Row: Toggle Buttons Row + const SizedBox(height: 10), + 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"), + ], + ), ), - padding: const EdgeInsets.all(15), - child: Row( + ], + ), + const SizedBox(height: 20), + + // Second Row: Domestic & International and Status + isDesktop + ? Row( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ - ...typeData.map((item) { - return Expanded( - child: Column( - children: [ - buildTopCard( - color: item['value'] == "Domestic" - ? Color(0xFF0DB04B) - : Color(0xFF004A8E), - label: item['value'], - count: item['count'], - bgColor: item['value'] == "Domestic" - ? const Color(0xFFD6FBE4) - : const Color(0xFFD9E8FF), + 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), ), ], ), - ); - }).toList(), - ], - ), - ), - ), - const SizedBox(width: 20), - 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, + padding: const EdgeInsets.all( + 15, + ), + child: Row( + children: [ + ...typeData.map((item) { + return Expanded( + child: Column( + children: [ + buildTopCard( + 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(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - ...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(), - ], + const SizedBox(width: 20), + 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: 10, + ), + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceAround, + children: [ + ...statusData + .map( + ( + item, + ) => statusCard( + item['value'], + item['count'], + isDesktop, + ), + ) + .toList(), + ], + ), + ], + ), + ), ), ], - ), - ), - ), - ], - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - 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: [ - ...typeData.map((item) { - return Expanded( - child: Column( - children: [ - buildTopCard( - color: item['value'] == "Domestic" - ? const Color(0xFF0DB04B) - : const Color(0xFF004A8E), - label: item['value'], - count: item['count'], - bgColor: item['value'] == "Domestic" - ? const Color(0xFFD6FBE4) - : const Color(0xFFD9E8FF), + ) + : Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: + BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.blueGrey, + blurRadius: 5, + offset: Offset(0, 2), ), ], ), - ); - }).toList(), - ], - ), - ), - const SizedBox(height: 20), - 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, + padding: const EdgeInsets.all( + 15, + ), + child: Row( + children: [ + ...typeData.map((item) { + return Expanded( + child: Column( + children: [ + buildTopCard( + color: + item['value'] == + "Domestic" + ? const Color( + 0xFF0DB04B, + ) + : const Color( + 0xFF004A8E, + ), + label: + item['value'], + count: + item['count'], + bgColor: + item['value'] == + "Domestic" + ? const Color( + 0xFFD6FBE4, + ) + : const Color( + 0xFFD9E8FF, + ), + ), + ], + ), + ); + }).toList(), + ], + ), ), - ), - const SizedBox(height: 23), - Wrap( - spacing: 10, - runSpacing: 10, - children: [ - ...statusData.map((item) => statusCard(item['value'], item['count'], isDesktop)).toList(), - ], - ), - ], - ), - ), - ], - ), + const SizedBox(height: 20), + 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), + Wrap( + spacing: 10, + runSpacing: 10, + children: [ + ...statusData + .map( + ( + item, + ) => statusCard( + item['value'], + item['count'], + isDesktop, + ), + ) + .toList(), + ], + ), + ], + ), + ), + ], + ), - const SizedBox(height: 20), + const SizedBox(height: 20), - // Third Row: Flight, Accommodation, Forex - isDesktop - ? 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)), + // Third Row: Flight, Accommodation, Forex + isDesktop + ? 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, + ), + ), + ], + ) + : Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: buildCategoryCard( + "Flight", + Icons.flight, + statusLabels, + flightData, + ), + ), + ], + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: buildCategoryCard( + "Accomodation", + Icons.hotel_outlined, + statusLabels, + accommodationData, + ), + ), + ], + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: buildCategoryCard( + "Forex", + Icons.attach_money, + statusLabels, + forexData, + ), + ), + ], + ), + const SizedBox(height: 20), + ], + ), ], - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded(child: buildCategoryCard("Flight", Icons.flight, statusLabels, flightData)), - ], - ), - const SizedBox(height: 20), - Row( - children: [ - Expanded(child: buildCategoryCard("Accomodation", Icons.hotel_outlined, statusLabels, accommodationData)), - ], - ), - const SizedBox(height: 20), - Row( - children: [ - Expanded(child: buildCategoryCard("Forex", Icons.attach_money, statusLabels, forexData)), - ], - ), - const SizedBox(height: 20), - ], - ), - ], - ); - }, - ) , + ); + }, + ), ], ), ), diff --git a/lib/Screens/itnerary/flights.dart b/lib/Screens/itnerary/flights.dart index f30cb2c..27da3a6 100644 --- a/lib/Screens/itnerary/flights.dart +++ b/lib/Screens/itnerary/flights.dart @@ -655,7 +655,7 @@ class FlightScreenState extends State { errorMessages["date_$i"] = "Required"; } - if( selectedClasses[i] == null ) { + if (selectedClasses[i] == null) { errorMessages["class_$i"] = "Required"; } if (textControllers["_time${i}Controller"]?.text.trim().isEmpty ?? true) { @@ -926,9 +926,10 @@ class FlightScreenState extends State { alignment: Alignment.centerRight, child: ElevatedButton( style: ElevatedButton.styleFrom( - minimumSize: !isDesktop - ? const Size.fromHeight(48) - : null, // No min height on desktop // height + minimumSize: + !isDesktop + ? const Size.fromHeight(48) + : null, // No min height on desktop // height backgroundColor: Colors.green, foregroundColor: Colors.white, shape: RoundedRectangleBorder( @@ -1534,1880 +1535,2012 @@ class FlightScreenState extends State { return isDesktop ? [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "From*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // isFocused: _fromFocus, - // isFocused: focusStates["_from${index}Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - // isFocused: focusStates["_from${fieldIndex}Focused"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "From*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // isFocused: _fromFocus, + // isFocused: focusStates["_from${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + // isFocused: focusStates["_from${fieldIndex}Focused"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: isCountryLoading ? Center(child: CircularProgressIndicator()) : Focus( - focusNode: focusNodes["_from${index}FocusNode"], - onFocusChange: (hasFocus) { - setState(() { - focusStates["_from${index}Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_from${index}FocusNode"] - ?.requestFocus(); - }, - child: DropdownSearch( - enabled: - !(selectedTripType == "Roundtrip" && - index == 2), - selectedItem: - selectedFrom[index] != null - ? countryMap[selectedFrom[index]] - : null, - items: countryMap.values.toList(), - // asyncItems: (String filter) async { - // final allItems = countryMap.values.toSet().toList(); - // print("Original items: ${allItems.length}"); - // final filtered = filterAndSortCountryList(allItems, filter); - // // print("Filtered items: ${filtered.length} -> $filtered"); - // return filtered; - // }, - popupProps: PopupProps.menu( - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 220), - showSearchBox: - true, // Enables search functionality - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 1, + focusNode: focusNodes["_from${index}FocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["_from${index}Focused"] = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_from${index}FocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch( + enabled: + !(selectedTripType == "Roundtrip" && + index == 2), + selectedItem: + selectedFrom[index] != null + ? countryMap[selectedFrom[index]] + : null, + items: countryMap.values.toList(), + // asyncItems: (String filter) async { + // final allItems = countryMap.values.toSet().toList(); + // print("Original items: ${allItems.length}"); + // final filtered = filterAndSortCountryList(allItems, filter); + // // print("Filtered items: ${filtered.length} -> $filtered"); + // return filtered; + // }, + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 220), + showSearchBox: + true, // Enables search functionality + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 1, + ), + ), + style: TextStyle(fontSize: 12), ), - ), - style: TextStyle(fontSize: 12), - ), - menuProps: MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: (context, item, isSelected) { - final parts = item.split('\n'); - final cityAndCode = parts[0]; - final airport = - parts.length > 1 ? parts[1] : ''; - - // Extract city and code from "City (CODE)" - final cityMatch = RegExp( - r'^(.*)\s+\(([^)]+)\)$', - ).firstMatch(cityAndCode); - final city = cityMatch?.group(1) ?? ''; - final code = cityMatch?.group(2) ?? ''; - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, + menuProps: MenuProps( + backgroundColor: Colors.white, ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, + itemBuilder: (context, item, isSelected) { + final parts = item.split('\n'); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 ? parts[1] : ''; + + // Extract city and code from "City (CODE)" + final cityMatch = RegExp( + r'^(.*)\s+\(([^)]+)\)$', + ).firstMatch(cityAndCode); + final city = cityMatch?.group(1) ?? ''; + final code = cityMatch?.group(2) ?? ''; + + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, children: [ - Text( - city, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + city, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + Text( + code, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], ), + const SizedBox(height: 1), Text( - code, + airport, style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, + fontSize: 11, + color: Colors.grey, + overflow: TextOverflow.ellipsis, ), ), ], ), - const SizedBox(height: 1), - Text( - airport, - style: const TextStyle( - fontSize: 11, - color: Colors.grey, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ); - }, + ); + }, - // itemBuilder: - // (context, item, isSelected) => Padding( - // padding: const EdgeInsets.symmetric( - // horizontal: 8.0, - // vertical: 6.0, - // ), - // child: Text( - // item, - // style: TextStyle( - // fontSize: 13, - // ), // 👈 Set your desired text size here - // ), - // ), - ), - // items: countryMap.values.toList(), - // filterFn: (item, filter) { - // final lowerFilter = filter.toLowerCase(); - // - // final parts = item.split('\n'); - // final cityAndCode = parts[0]; - // final airport = parts.length > 1 ? parts[1].toLowerCase() : ''; - // - // // Extract city and code from "City (CODE)" - // final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode); - // final city = cityMatch?.group(1)?.toLowerCase() ?? ''; - // final code = cityMatch?.group(2)?.toLowerCase() ?? ''; - // - // // Priority: Code > City > Airport - // return code.contains(lowerFilter) || - // city.contains(lowerFilter) || - // airport.contains(lowerFilter); - // }, - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_from${index}Focused"] ?? - false) - ? layoutColor! - : Colors.white, - width: 0.5, + // itemBuilder: + // (context, item, isSelected) => Padding( + // padding: const EdgeInsets.symmetric( + // horizontal: 8.0, + // vertical: 6.0, + // ), + // child: Text( + // item, + // style: TextStyle( + // fontSize: 13, + // ), // 👈 Set your desired text size here + // ), + // ), + ), + // items: countryMap.values.toList(), + // filterFn: (item, filter) { + // final lowerFilter = filter.toLowerCase(); + // + // final parts = item.split('\n'); + // final cityAndCode = parts[0]; + // final airport = parts.length > 1 ? parts[1].toLowerCase() : ''; + // + // // Extract city and code from "City (CODE)" + // final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode); + // final city = cityMatch?.group(1)?.toLowerCase() ?? ''; + // final code = cityMatch?.group(2)?.toLowerCase() ?? ''; + // + // // Priority: Code > City > Airport + // return code.contains(lowerFilter) || + // city.contains(lowerFilter) || + // airport.contains(lowerFilter); + // }, + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_from${index}Focused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_from${index}Focused"] ?? + false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), ), ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_from${index}Focused"] ?? - false) - ? layoutColor - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: layoutColor, - width: 1, - ), - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null) { + return Align( + alignment: Alignment.centerLeft, + child: const Text( + "Select", + style: TextStyle(fontSize: 12), + ), + ); + } + + final parts = selectedItem.split('\n'); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 ? parts[1] : ''; + + return Align( + alignment: Alignment.centerLeft, + child: Text( + cityAndCode ?? "Select", + style: const TextStyle(fontSize: 12), + ), + ); + }, + + // dropdownBuilder: + // (context, selectedItem) => Align( + // alignment: Alignment.centerLeft, + // child: Text( + // selectedItem ?? "Select", + // style: TextStyle(fontSize: 12), + // ), + // ), + onChanged: (String? newValue) { + setState(() { + errorMessages.remove("from_place_$index"); + // selectedFrom[index] = countryMap.entries + // .firstWhere((entry) => entry.value == newValue) + // .key; + + selectedFrom[index] = + countryMap.entries + .firstWhere( + (entry) => + entry.value == newValue, + ) + .key; + if (selectedTripType == "Roundtrip") { + print('rounfTo${selectedFrom[index]}'); + // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; + selectedTo[2] = selectedFrom[index]!; + } + }); + }, ), ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null) { - return Align( - alignment: Alignment.centerLeft, - child: const Text( - "Select", - style: TextStyle(fontSize: 12), - ), - ); - } - - final parts = selectedItem.split('\n'); - final cityAndCode = parts[0]; - final airport = parts.length > 1 ? parts[1] : ''; - - return Align( - alignment: Alignment.centerLeft, - child: Text( - cityAndCode ?? "Select", - style: const TextStyle(fontSize: 12), - ), - ); - }, - - // dropdownBuilder: - // (context, selectedItem) => Align( - // alignment: Alignment.centerLeft, - // child: Text( - // selectedItem ?? "Select", - // style: TextStyle(fontSize: 12), - // ), - // ), - onChanged: (String? newValue) { - setState(() { - errorMessages.remove("from_place_$index"); - // selectedFrom[index] = countryMap.entries - // .firstWhere((entry) => entry.value == newValue) - // .key; - - selectedFrom[index] = - countryMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; - if (selectedTripType == "Roundtrip") { - print('rounfTo${selectedFrom[index]}'); - // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; - selectedTo[2] = selectedFrom[index]!; - } - }); - }, ), - ), - ), - ), + ), - // child: SizedBox( - // height: 40, - // child: TextField( - // // focusNode: _fromFocusNode, - // focusNode: focusNodes["_from${index}FocusNode"], - // controller: textControllers["_from${index}Controller"], - // style: const TextStyle(fontSize: 12), - // decoration: const InputDecoration( - // labelText: "From", - // labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - // floatingLabelBehavior: FloatingLabelBehavior.never, - // border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric(vertical: 16), - // ), - // ), - // ), - ), - if (errorMessages["from_place_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["from_place_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], + // child: SizedBox( + // height: 40, + // child: TextField( + // // focusNode: _fromFocusNode, + // focusNode: focusNodes["_from${index}FocusNode"], + // controller: textControllers["_from${index}Controller"], + // style: const TextStyle(fontSize: 12), + // decoration: const InputDecoration( + // labelText: "From", + // labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + // floatingLabelBehavior: FloatingLabelBehavior.never, + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(vertical: 16), + // ), + // ), + // ), ), - if (isDesktop) SizedBox(width: 20) else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "To*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // isFocused: focusStates["_to${index}Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: + if (errorMessages["from_place_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["from_place_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) SizedBox(width: 20) else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "To*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // isFocused: focusStates["_to${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: isCountryLoading ? Center(child: CircularProgressIndicator()) : Focus( - focusNode: focusNodes["_to${index}FocusNode"], - onFocusChange: (hasFocus) { - setState(() { - focusStates["_to${index}Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_to${index}FocusNode"]?.requestFocus(); - }, - child: DropdownSearch( - enabled: - !(selectedTripType == "Roundtrip" && - index == 2), - selectedItem: - selectedTo[index] != null - ? countryMap[selectedTo[index]] - : null, - popupProps: PopupProps.menu( - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 220), - showSearchBox: - true, // Enables search functionality - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 1, + focusNode: focusNodes["_to${index}FocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["_to${index}Focused"] = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_to${index}FocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch( + enabled: + !(selectedTripType == "Roundtrip" && + index == 2), + selectedItem: + selectedTo[index] != null + ? countryMap[selectedTo[index]] + : null, + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 220), + showSearchBox: + true, // Enables search functionality + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 1, + ), + ), + style: TextStyle(fontSize: 12), ), - ), - style: TextStyle(fontSize: 12), - ), - menuProps: MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: (context, item, isSelected) { - final parts = item.split('\n'); - final cityAndCode = parts[0]; - final airport = - parts.length > 1 ? parts[1] : ''; - - // Extract city and code from "City (CODE)" - final cityMatch = RegExp( - r'^(.*)\s+\(([^)]+)\)$', - ).firstMatch(cityAndCode); - final city = cityMatch?.group(1) ?? ''; - final code = cityMatch?.group(2) ?? ''; - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, + menuProps: MenuProps( + backgroundColor: Colors.white, ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, + itemBuilder: (context, item, isSelected) { + final parts = item.split('\n'); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 ? parts[1] : ''; + + // Extract city and code from "City (CODE)" + final cityMatch = RegExp( + r'^(.*)\s+\(([^)]+)\)$', + ).firstMatch(cityAndCode); + final city = cityMatch?.group(1) ?? ''; + final code = cityMatch?.group(2) ?? ''; + + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, children: [ - Text( - city, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + city, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + Text( + code, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ], ), + const SizedBox(height: 1), Text( - code, + airport, style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, + fontSize: 11, + color: Colors.grey, + overflow: TextOverflow.ellipsis, ), ), ], ), - const SizedBox(height: 1), - Text( - airport, - style: const TextStyle( - fontSize: 11, - color: Colors.grey, - overflow: TextOverflow.ellipsis, - ), + ); + }, + // itemBuilder: + // (context, item, isSelected) => Padding( + // padding: const EdgeInsets.symmetric( + // horizontal: 8.0, + // vertical: 6.0, + // ), + // child: Text( + // item, + // style: TextStyle( + // fontSize: 13, + // ), // 👈 Set your desired text size here + // ), + // ), + ), + items: countryMap.values.toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_to${index}Focused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, ), - ], - ), - ); - }, - // itemBuilder: - // (context, item, isSelected) => Padding( - // padding: const EdgeInsets.symmetric( - // horizontal: 8.0, - // vertical: 6.0, - // ), - // child: Text( - // item, - // style: TextStyle( - // fontSize: 13, - // ), // 👈 Set your desired text size here - // ), - // ), - ), - items: countryMap.values.toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_to${index}Focused"] ?? - false) - ? layoutColor! - : Colors.white, - width: 0.5, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_to${index}Focused"] ?? + false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), ), ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_to${index}Focused"] ?? - false) - ? layoutColor - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: layoutColor, - width: 1, - ), - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), + + // dropdownBuilder: + // (context, selectedItem) => Align( + // alignment: Alignment.centerLeft, + // child: Text( + // selectedItem ?? "Select Country", + // style: TextStyle(fontSize: 12), + // ), + // ), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null) { + return Align( + alignment: Alignment.centerLeft, + child: const Text( + "Select", + style: TextStyle(fontSize: 12), + ), + ); + } + + final parts = selectedItem.split('\n'); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 ? parts[1] : ''; + + return Align( + alignment: Alignment.centerLeft, + child: Text( + cityAndCode ?? "Select", + style: const TextStyle(fontSize: 12), + ), + ); + }, + onChanged: (String? newValue) { + setState(() { + errorMessages.remove("to_place_$index"); + selectedTo[index] = + countryMap.entries + .firstWhere( + (entry) => + entry.value == newValue, + ) + .key; + + print(selectedTo[index]); + + if (selectedTripType == "Roundtrip") { + print('rounfTo${selectedTo[index]}'); + // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; + selectedFrom[2] = selectedTo[index]!; + } + }); + }, ), ), - - // dropdownBuilder: - // (context, selectedItem) => Align( - // alignment: Alignment.centerLeft, - // child: Text( - // selectedItem ?? "Select Country", - // style: TextStyle(fontSize: 12), - // ), - // ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null) { - return Align( - alignment: Alignment.centerLeft, - child: const Text( - "Select", - style: TextStyle(fontSize: 12), - ), - ); - } - - final parts = selectedItem.split('\n'); - final cityAndCode = parts[0]; - final airport = parts.length > 1 ? parts[1] : ''; - - return Align( - alignment: Alignment.centerLeft, - child: Text( - cityAndCode ?? "Select", - style: const TextStyle(fontSize: 12), - ), - ); - }, - onChanged: (String? newValue) { - setState(() { - errorMessages.remove("to_place_$index"); - selectedTo[index] = - countryMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; - - print(selectedTo[index]); - - if (selectedTripType == "Roundtrip") { - print('rounfTo${selectedTo[index]}'); - // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; - selectedFrom[2] = selectedTo[index]!; - } - }); - }, ), - ), - ), - ), - ), - if (errorMessages["to_place_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["to_place_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], + ), ), - if (isDesktop) Spacer() else SizedBox(height: 8), + if (errorMessages["to_place_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["to_place_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Class *", - // style: GoogleFonts.poppins( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // color: Color(0xFF575A74), - // ), - // ), - // SizedBox(height: 5), - // CustomTextFieldItnerarySubWrapper( - // isFocused: focusStates["_class${index}Focused"] ?? false, - // isDesktop: isDesktop, - // // width: isDesktop - // // ? MediaQuery.of(context).size.width * 0.34 - // // : MediaQuery.of(context).size.width * 0.66, - // child: SizedBox( - // height: 40, - // child: - // isFlightClassLoading - // ? const Center(child: CircularProgressIndicator()) - // : DropdownButtonFormField( - // focusNode: focusNodes["_class${index}FocusNode"], - // // focusNode: _tripTypeFocusNode, // Assign the correct focus node - // // controller: _hotelNameController, - // value: selectedClasses[index], - // - // style: TextStyle(fontSize: 12), - // decoration: InputDecoration( - // border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric( - // horizontal: 10, - // ), // Proper padding - // ), - // onChanged: - // purposeList.isNotEmpty - // ? (newValue) { - // setState(() { - // selectedClasses[index] = newValue; - // }); - // - // print(selectedClasses[index]); - // } - // : null, - // items: dropdownItems, - // ), - // ), - // ), - // ], - // ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Class *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // isFocused: focusStates["_class${index}Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - isDesktop: isDesktop, - child: SizedBox( - height: 40, - width: double.infinity, - child: Focus( - focusNode: focusNodes["_class${index}FocusNode"], + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Text( + // "Class *", + // style: GoogleFonts.poppins( + // fontSize: 12, + // fontWeight: FontWeight.w600, + // color: Color(0xFF575A74), + // ), + // ), + // SizedBox(height: 5), + // CustomTextFieldItnerarySubWrapper( + // isFocused: focusStates["_class${index}Focused"] ?? false, + // isDesktop: isDesktop, + // // width: isDesktop + // // ? MediaQuery.of(context).size.width * 0.34 + // // : MediaQuery.of(context).size.width * 0.66, + // child: SizedBox( + // height: 40, + // child: + // isFlightClassLoading + // ? const Center(child: CircularProgressIndicator()) + // : DropdownButtonFormField( + // focusNode: focusNodes["_class${index}FocusNode"], + // // focusNode: _tripTypeFocusNode, // Assign the correct focus node + // // controller: _hotelNameController, + // value: selectedClasses[index], + // + // style: TextStyle(fontSize: 12), + // decoration: InputDecoration( + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric( + // horizontal: 10, + // ), // Proper padding + // ), + // onChanged: + // purposeList.isNotEmpty + // ? (newValue) { + // setState(() { + // selectedClasses[index] = newValue; + // }); + // + // print(selectedClasses[index]); + // } + // : null, + // items: dropdownItems, + // ), + // ), + // ), + // ], + // ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Class *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // isFocused: focusStates["_class${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + isDesktop: isDesktop, + child: SizedBox( + height: 40, + width: double.infinity, + child: Focus( + focusNode: focusNodes["_class${index}FocusNode"], - onFocusChange: (hasFocus) { - setState(() { - focusStates["_class${index}Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_class${index}FocusNode"]?.requestFocus(); - }, - child: DropdownSearch>( - items: purposeList.cast>(), - key: + onFocusChange: (hasFocus) { + setState(() { + focusStates["_class${index}Focused"] = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_class${index}FocusNode"]?.requestFocus(); + }, + child: DropdownSearch>( + items: purposeList.cast>(), + key: selectedClasses[index] == null ? UniqueKey() : ValueKey(selectedClasses[index]), - // selectedItem: purposeList.firstWhere( - // (item) => item['dropdown_key'] == selectedClasses[index], - // orElse: () => {}, - // ), - selectedItem: + // selectedItem: purposeList.firstWhere( + // (item) => item['dropdown_key'] == selectedClasses[index], + // orElse: () => {}, + // ), + selectedItem: selectedClasses[index] != null ? purposeList.firstWhere( (item) => - item['dropdown_key'] == - selectedClasses[index], - orElse: () => {}, - ) + item['dropdown_key'] == + selectedClasses[index], + orElse: () => {}, + ) : null, - itemAsString: (item) => item['dropdown_value'] ?? '', - popupProps: PopupProps.menu( - showSearchBox: false, - fit: FlexFit.loose, - menuProps: const MenuProps(backgroundColor: Colors.white), - itemBuilder: (context, item, isSelected) { - final bool isNotAllowed = item['is_allowed'] == 'No'; - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 8, - ), - child: Text( - item['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: + itemAsString: (item) => item['dropdown_value'] ?? '', + popupProps: PopupProps.menu( + showSearchBox: false, + fit: FlexFit.loose, + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: (context, item, isSelected) { + final bool isNotAllowed = + item['is_allowed'] == 'No'; + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, + ), + child: Text( + item['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: isNotAllowed ? Colors.redAccent : Colors.black, - ), - ), - ); - }, - ), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - // border: InputBorder.none, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_class${index}Focused"] ?? false) + ), + ), + ); + }, + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_class${index}Focused"] ?? + false) ? layoutColor! : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_class${index}Focused"] ?? false) + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_class${index}Focused"] ?? + false) ? layoutColor : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: layoutColor, width: 1), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), ), ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Class", - style: GoogleFonts.poppins( - color: Colors.grey, - fontSize: 13, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ); - }, - onChanged: + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || selectedItem.isEmpty) { + return Text( + "Select Class", + style: GoogleFonts.poppins( + color: Colors.grey, + fontSize: 13, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ); + }, + onChanged: purposeList.isNotEmpty ? (Map? newValue) async { - // if (newValue != null && - // newValue['is_allowed'] == 'No') { - // print('not allowed'); - // - // exceptionalClass[index] = "1"; - // } else if (newValue != null && - // newValue['is_allowed'] == 'yes') { - // print('not allowed'); - // - // exceptionalClass[index] = "0"; - // } - // - // setState(() { - // selectedClasses[index] = - // newValue?['dropdown_key']; - // print( - // "Selected Class: ${selectedClasses[index]}", - // ); - // }); - - if (newValue != null && - newValue['is_allowed'] == 'No') { - final confirm = await showNotAllowedDialog( - context, - message: - "You are not entitled for this service. If you wish to continue with this service, you may require another approval.", - ); - - if (confirm) { - setState(() { - exceptionalClass[index] = "1"; - selectedClasses[index] = - newValue['dropdown_key']; - }); - print( - "Selected Purpose: ${selectedClasses[index]}", - ); - } else { - setState(() { - exceptionalClass[index] = "0"; - selectedClasses[index] = - null; // ❌ Clear selection if user cancels - }); - print( - "selectedItem resolved to: ${selectedClasses[index]}", - ); - } - - return; - } else if (newValue != null && - newValue['is_allowed'] == 'yes') { - setState(() { - exceptionalClass[index] = "0"; - selectedClasses[index] = - newValue?['dropdown_key']; - print( - "Selected Purpose: ${selectedClasses[index]}", - ); - }); - } - } - : null, - ), - ), - ), - ), - ), - if (errorMessages["class_$index"] != null) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - errorMessages["class_$index"]!, - style: GoogleFonts.poppins(fontSize: 12, color: Colors.red), - ), - ), - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Date*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_date${index}Focused"] ?? false, - - isDesktop: isDesktop, - width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () { - focusNodes["_date${index}FocusNode"]?.requestFocus(); - _selectCheckOutDate(context); - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["_date${index}FocusNode"], - // controller: _dateController, - controller: textControllers["_date${index}Controller"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: InputDecoration( - labelText: "Select Date", - labelStyle: const TextStyle( - fontSize: 12, - color: Colors.grey, - ), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // borderSide: BorderSide( - // color: - // (focusStates["_date${index}Focused"] ?? false) - // ? layoutColor! - // : Colors.white, - // width: 0.5, - // ), - // ), - // enabledBorder: OutlineInputBorder( - // borderSide: BorderSide( - // color: - // (focusStates["_date${index}Focused"] ?? false) - // ? layoutColor - // : Colors.white, - // // : const Color(0xFFD6D5E6), - // width: 0.5, - // // const Color(0xFFD6D5E6), - // ), - // ), - // focusedBorder: OutlineInputBorder( - // borderSide: BorderSide(color: layoutColor, width: 1), - // ), - // contentPadding: const EdgeInsets.symmetric( - // horizontal: 10, - // vertical: 5, - // ), - suffixIcon: const Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["date_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["date_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Time*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_time${index}Focused"] ?? false, - isDesktop: isDesktop, - width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () { - focusNodes["_time${index}FocusNode"]?.requestFocus(); - textControllers["_time${index}Controller"]?.text = ""; - _clearError("time_$index"); - // validateTimeDifference(index); - // _selectCheckOutTime(context); - - _selectCheckOutTime(context, index, () { - validateTimeDifference(index); - setState( - () {}, - ); // ✅ Force rebuild to show the error immediately - }); - }, - - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["_time${index}FocusNode"], - // controller: _timeController, - controller: textControllers["_time${index}Controller"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - labelText: "Time", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - suffixIcon: Icon( - Icons.access_time, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - // Focus( - // focusNode: focusNodes["_time${index}FocusNode"], - // onFocusChange: (hasFocus) { - // setState(() { - // focusStates["_time${index}Focused"] = hasFocus; - // }); - // }, - // child: GestureDetector( - // // - // onTap: () { - // // Request focus when user taps - // focusNodes["_time${index}FocusNode"]?.requestFocus(); - // }, - ), - ), - ), - if (errorMessages["time_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["time_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (selectedTripType == "Multitrip") - Container( - // color: Colors.blueGrey, - // padding: const EdgeInsets.only(top: 50, bottom: 50), - child: IconButton( - onPressed: () { - removeTrip(index); - }, - icon: Icon(Icons.close, color: Colors.redAccent, size: 20), - ), - ), - ] - : [ - // For mobile, wrap inside a card with padding and grey background - Card( - elevation: 1, - margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), - color: const Color(0xFFF5F5F5), // Light grey - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "From*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // isFocused: _fromFocus, - // isFocused: focusStates["_from${index}Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - // isFocused: focusStates["_from${fieldIndex}Focused"] ?? false, - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: - isCountryLoading - ? Center(child: CircularProgressIndicator()) - : Focus( - focusNode: focusNodes["_from${index}FocusNode"], - onFocusChange: (hasFocus) { - setState(() { - focusStates["_from${index}Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_from${index}FocusNode"] - ?.requestFocus(); - }, - child: DropdownSearch( - enabled: - !(selectedTripType == "Roundtrip" && - index == 2), - selectedItem: - selectedFrom[index] != null - ? countryMap[selectedFrom[index]] - : null, - items: countryMap.values.toList(), - // asyncItems: (String filter) async { - // final allItems = countryMap.values.toSet().toList(); - // print("Original items: ${allItems.length}"); - // final filtered = filterAndSortCountryList(allItems, filter); - // // print("Filtered items: ${filtered.length} -> $filtered"); - // return filtered; - // }, - popupProps: PopupProps.menu( - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 220), - showSearchBox: - true, // Enables search functionality - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 1, - ), - ), - style: TextStyle(fontSize: 12), - ), - menuProps: MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: (context, item, isSelected) { - final parts = item.split('\n'); - final cityAndCode = parts[0]; - final airport = - parts.length > 1 ? parts[1] : ''; - - // Extract city and code from "City (CODE)" - final cityMatch = RegExp( - r'^(.*)\s+\(([^)]+)\)$', - ).firstMatch(cityAndCode); - final city = cityMatch?.group(1) ?? ''; - final code = cityMatch?.group(2) ?? ''; - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, - ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - city, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - Text( - code, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 1), - Text( - airport, - style: const TextStyle( - fontSize: 11, - color: Colors.grey, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ); - }, - - // itemBuilder: - // (context, item, isSelected) => Padding( - // padding: const EdgeInsets.symmetric( - // horizontal: 8.0, - // vertical: 6.0, - // ), - // child: Text( - // item, - // style: TextStyle( - // fontSize: 13, - // ), // 👈 Set your desired text size here - // ), - // ), - ), - // items: countryMap.values.toList(), - // filterFn: (item, filter) { - // final lowerFilter = filter.toLowerCase(); + // if (newValue != null && + // newValue['is_allowed'] == 'No') { + // print('not allowed'); // - // final parts = item.split('\n'); - // final cityAndCode = parts[0]; - // final airport = parts.length > 1 ? parts[1].toLowerCase() : ''; + // exceptionalClass[index] = "1"; + // } else if (newValue != null && + // newValue['is_allowed'] == 'yes') { + // print('not allowed'); // - // // Extract city and code from "City (CODE)" - // final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode); - // final city = cityMatch?.group(1)?.toLowerCase() ?? ''; - // final code = cityMatch?.group(2)?.toLowerCase() ?? ''; + // exceptionalClass[index] = "0"; + // } // - // // Priority: Code > City > Airport - // return code.contains(lowerFilter) || - // city.contains(lowerFilter) || - // airport.contains(lowerFilter); - // }, - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_from${index}Focused"] ?? - false) - ? layoutColor! - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_from${index}Focused"] ?? - false) - ? layoutColor - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: layoutColor, - width: 1, - ), - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - ), - ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null) { - return Align( - alignment: Alignment.centerLeft, - child: const Text( - "Select", - style: TextStyle(fontSize: 12), - ), - ); - } + // setState(() { + // selectedClasses[index] = + // newValue?['dropdown_key']; + // print( + // "Selected Class: ${selectedClasses[index]}", + // ); + // }); - final parts = selectedItem.split('\n'); - final cityAndCode = parts[0]; - final airport = parts.length > 1 ? parts[1] : ''; - - return Align( - alignment: Alignment.centerLeft, - child: Text( - cityAndCode ?? "Select", - style: const TextStyle(fontSize: 12), - ), + if (newValue != null && + newValue['is_allowed'] == 'No') { + final confirm = await showNotAllowedDialog( + context, + message: + "You are not entitled for this service. If you wish to continue with this service, you may require another approval.", ); - }, - // dropdownBuilder: - // (context, selectedItem) => Align( - // alignment: Alignment.centerLeft, - // child: Text( - // selectedItem ?? "Select", - // style: TextStyle(fontSize: 12), - // ), - // ), - onChanged: (String? newValue) { - setState(() { - errorMessages.remove("from_place_$index"); - // selectedFrom[index] = countryMap.entries - // .firstWhere((entry) => entry.value == newValue) - // .key; - - selectedFrom[index] = - countryMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; - if (selectedTripType == "Roundtrip") { - print('rounfTo${selectedFrom[index]}'); - // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; - selectedTo[2] = selectedFrom[index]!; - } - }); - }, - ), - ), - ), - ), - - // child: SizedBox( - // height: 40, - // child: TextField( - // // focusNode: _fromFocusNode, - // focusNode: focusNodes["_from${index}FocusNode"], - // controller: textControllers["_from${index}Controller"], - // style: const TextStyle(fontSize: 12), - // decoration: const InputDecoration( - // labelText: "From", - // labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - // floatingLabelBehavior: FloatingLabelBehavior.never, - // border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric(vertical: 16), - // ), - // ), - // ), - ), - if (errorMessages["from_place_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["from_place_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (isDesktop) SizedBox(width: 20) else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "To*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // isFocused: focusStates["_to${index}Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - isDesktop: isDesktop, - child: SizedBox( - height: 40, - child: - isCountryLoading - ? Center(child: CircularProgressIndicator()) - : Focus( - focusNode: focusNodes["_to${index}FocusNode"], - onFocusChange: (hasFocus) { - setState(() { - focusStates["_to${index}Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_to${index}FocusNode"]?.requestFocus(); - }, - child: DropdownSearch( - enabled: - !(selectedTripType == "Roundtrip" && - index == 2), - selectedItem: - selectedTo[index] != null - ? countryMap[selectedTo[index]] - : null, - popupProps: PopupProps.menu( - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 220), - showSearchBox: - true, // Enables search functionality - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 1, - ), - ), - style: TextStyle(fontSize: 12), - ), - menuProps: MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: (context, item, isSelected) { - final parts = item.split('\n'); - final cityAndCode = parts[0]; - final airport = - parts.length > 1 ? parts[1] : ''; - - // Extract city and code from "City (CODE)" - final cityMatch = RegExp( - r'^(.*)\s+\(([^)]+)\)$', - ).firstMatch(cityAndCode); - final city = cityMatch?.group(1) ?? ''; - final code = cityMatch?.group(2) ?? ''; - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 6.0, - ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - city, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - Text( - code, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 1), - Text( - airport, - style: const TextStyle( - fontSize: 11, - color: Colors.grey, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), + if (confirm) { + setState(() { + exceptionalClass[index] = "1"; + selectedClasses[index] = + newValue['dropdown_key']; + }); + print( + "Selected Purpose: ${selectedClasses[index]}", ); - }, - // itemBuilder: - // (context, item, isSelected) => Padding( - // padding: const EdgeInsets.symmetric( - // horizontal: 8.0, - // vertical: 6.0, - // ), - // child: Text( - // item, - // style: TextStyle( - // fontSize: 13, - // ), // 👈 Set your desired text size here - // ), - // ), - ), - items: countryMap.values.toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_to${index}Focused"] ?? - false) - ? layoutColor! - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_to${index}Focused"] ?? - false) - ? layoutColor - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: layoutColor, - width: 1, - ), - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - ), - ), - - // dropdownBuilder: - // (context, selectedItem) => Align( - // alignment: Alignment.centerLeft, - // child: Text( - // selectedItem ?? "Select Country", - // style: TextStyle(fontSize: 12), - // ), - // ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null) { - return Align( - alignment: Alignment.centerLeft, - child: const Text( - "Select", - style: TextStyle(fontSize: 12), - ), - ); - } - - final parts = selectedItem.split('\n'); - final cityAndCode = parts[0]; - final airport = parts.length > 1 ? parts[1] : ''; - - return Align( - alignment: Alignment.centerLeft, - child: Text( - cityAndCode ?? "Select", - style: const TextStyle(fontSize: 12), - ), - ); - }, - onChanged: (String? newValue) { - setState(() { - errorMessages.remove("to_place_$index"); - selectedTo[index] = - countryMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; - - print(selectedTo[index]); - - if (selectedTripType == "Roundtrip") { - print('rounfTo${selectedTo[index]}'); - // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; - selectedFrom[2] = selectedTo[index]!; - } - }); - }, - ), - ), - ), - ), - ), - if (errorMessages["to_place_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["to_place_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Class *", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // isFocused: focusStates["_class${index}Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - isDesktop: isDesktop, - child: SizedBox( - height: 40, - width: double.infinity, - child: Focus( - focusNode: focusNodes["_class${index}FocusNode"], - - onFocusChange: (hasFocus) { - setState(() { - focusStates["_class${index}Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_class${index}FocusNode"]?.requestFocus(); - }, - child: DropdownSearch>( - items: purposeList.cast>(), - key: - selectedClasses[index] == null - ? UniqueKey() - : ValueKey(selectedClasses[index]), - // selectedItem: purposeList.firstWhere( - // (item) => item['dropdown_key'] == selectedClasses[index], - // orElse: () => {}, - // ), - selectedItem: - selectedClasses[index] != null - ? purposeList.firstWhere( - (item) => - item['dropdown_key'] == - selectedClasses[index], - orElse: () => {}, - ) - : null, - itemAsString: (item) => item['dropdown_value'] ?? '', - popupProps: PopupProps.menu( - showSearchBox: false, - fit: FlexFit.loose, - menuProps: const MenuProps(backgroundColor: Colors.white), - itemBuilder: (context, item, isSelected) { - final bool isNotAllowed = item['is_allowed'] == 'No'; - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 8, - ), - child: Text( - item['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: - isNotAllowed - ? Colors.redAccent - : Colors.black, - ), - ), - ); - }, - ), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - // border: InputBorder.none, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_class${index}Focused"] ?? false) - ? layoutColor! - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_class${index}Focused"] ?? false) - ? layoutColor - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: layoutColor, width: 1), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - ), - ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Class", - style: GoogleFonts.poppins( - color: Colors.grey, - fontSize: 13, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ); - }, - onChanged: - purposeList.isNotEmpty - ? (Map? newValue) async { - // if (newValue != null && - // newValue['is_allowed'] == 'No') { - // print('not allowed'); - // - // exceptionalClass[index] = "1"; - // } else if (newValue != null && - // newValue['is_allowed'] == 'yes') { - // print('not allowed'); - // - // exceptionalClass[index] = "0"; - // } - // - // setState(() { - // selectedClasses[index] = - // newValue?['dropdown_key']; - // print( - // "Selected Class: ${selectedClasses[index]}", - // ); - // }); - - if (newValue != null && - newValue['is_allowed'] == 'No') { - final confirm = await showNotAllowedDialog( - context, - message: - "You are not entitled for this service. If you wish to continue with this service, you may require another approval.", - ); - - if (confirm) { - setState(() { - exceptionalClass[index] = "1"; - selectedClasses[index] = - newValue['dropdown_key']; - }); - print( - "Selected Purpose: ${selectedClasses[index]}", - ); - } else { - setState(() { - exceptionalClass[index] = "0"; - selectedClasses[index] = - null; // ❌ Clear selection if user cancels - }); - print( - "selectedItem resolved to: ${selectedClasses[index]}", - ); - } - - return; - } else if (newValue != null && - newValue['is_allowed'] == 'yes') { + } else { setState(() { exceptionalClass[index] = "0"; selectedClasses[index] = - newValue?['dropdown_key']; - print( - "Selected Purpose: ${selectedClasses[index]}", - ); + null; // ❌ Clear selection if user cancels }); + print( + "selectedItem resolved to: ${selectedClasses[index]}", + ); } - } - : null, - ), - ), - ), - ), - ), - if (errorMessages["class_$index"] != null) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - errorMessages["class_$index"]!, - style: GoogleFonts.poppins(fontSize: 12, color: Colors.red), - ), - ), - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Date*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_date${index}Focused"] ?? false, - isDesktop: isDesktop, - width: isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () { - focusNodes["_date${index}FocusNode"]?.requestFocus(); - _selectCheckOutDate(context); - }, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["_date${index}FocusNode"], - // controller: _dateController, - controller: textControllers["_date${index}Controller"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: InputDecoration( - labelText: "Select Date", - labelStyle: const TextStyle( - fontSize: 12, - color: Colors.grey, - ), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // borderSide: BorderSide( - // color: - // (focusStates["_date${index}Focused"] ?? false) - // ? layoutColor! - // : Colors.white, - // width: 0.5, - // ), - // ), - // enabledBorder: OutlineInputBorder( - // borderSide: BorderSide( - // color: - // (focusStates["_date${index}Focused"] ?? false) - // ? layoutColor - // : Colors.white, - // // : const Color(0xFFD6D5E6), - // width: 0.5, - // // const Color(0xFFD6D5E6), - // ), - // ), - // focusedBorder: OutlineInputBorder( - // borderSide: BorderSide(color: layoutColor, width: 1), - // ), - // contentPadding: const EdgeInsets.symmetric( - // horizontal: 10, - // vertical: 5, - // ), - suffixIcon: const Icon( - Icons.calendar_today, - size: 16, - color: Colors.grey, - ), - ), - ), - ), - ), - ), - ), - if (errorMessages["date_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["date_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], - ), - if (isDesktop) Spacer() else SizedBox(height: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Time*", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_time${index}Focused"] ?? false, - isDesktop: isDesktop, - width: isDesktop ? MediaQuery.of(context).size.width * 0.1 : null, - child: SizedBox( - height: 40, - child: GestureDetector( - onTap: () { - focusNodes["_time${index}FocusNode"]?.requestFocus(); - textControllers["_time${index}Controller"]?.text = ""; - _clearError("time_$index"); - // validateTimeDifference(index); - // _selectCheckOutTime(context); - - _selectCheckOutTime(context, index, () { - validateTimeDifference(index); - setState( - () {}, - ); // ✅ Force rebuild to show the error immediately + return; + } else if (newValue != null && + newValue['is_allowed'] == 'yes') { + setState(() { + exceptionalClass[index] = "0"; + selectedClasses[index] = + newValue?['dropdown_key']; + print( + "Selected Purpose: ${selectedClasses[index]}", + ); }); - }, + } + } + : null, + ), + ), + ), + ), + ), + if (errorMessages["class_$index"] != null) + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + errorMessages["class_$index"]!, + style: GoogleFonts.poppins(fontSize: 12, color: Colors.red), + ), + ), + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Date*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + isFocused: focusStates["_date${index}Focused"] ?? false, - child: AbsorbPointer( - child: TextField( - focusNode: focusNodes["_time${index}FocusNode"], - // controller: _timeController, - controller: textControllers["_time${index}Controller"], - readOnly: true, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - labelText: "Time", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - suffixIcon: Icon( - Icons.access_time, - size: 16, - color: Colors.grey, + isDesktop: isDesktop, + width: + isDesktop ? MediaQuery.of(context).size.width * 0.11 : null, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () { + focusNodes["_date${index}FocusNode"]?.requestFocus(); + _selectCheckOutDate(context); + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["_date${index}FocusNode"], + // controller: _dateController, + controller: textControllers["_date${index}Controller"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + labelText: "Select Date", + labelStyle: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // borderSide: BorderSide( + // color: + // (focusStates["_date${index}Focused"] ?? false) + // ? layoutColor! + // : Colors.white, + // width: 0.5, + // ), + // ), + // enabledBorder: OutlineInputBorder( + // borderSide: BorderSide( + // color: + // (focusStates["_date${index}Focused"] ?? false) + // ? layoutColor + // : Colors.white, + // // : const Color(0xFFD6D5E6), + // width: 0.5, + // // const Color(0xFFD6D5E6), + // ), + // ), + // focusedBorder: OutlineInputBorder( + // borderSide: BorderSide(color: layoutColor, width: 1), + // ), + // contentPadding: const EdgeInsets.symmetric( + // horizontal: 10, + // vertical: 5, + // ), + suffixIcon: const Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + ), + ), + ), + if (errorMessages["date_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["date_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Time*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + isFocused: focusStates["_time${index}Focused"] ?? false, + isDesktop: isDesktop, + width: + isDesktop ? MediaQuery.of(context).size.width * 0.1 : null, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () { + focusNodes["_time${index}FocusNode"]?.requestFocus(); + textControllers["_time${index}Controller"]?.text = ""; + _clearError("time_$index"); + // validateTimeDifference(index); + // _selectCheckOutTime(context); + + _selectCheckOutTime(context, index, () { + validateTimeDifference(index); + setState( + () {}, + ); // ✅ Force rebuild to show the error immediately + }); + }, + + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["_time${index}FocusNode"], + // controller: _timeController, + controller: textControllers["_time${index}Controller"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + labelText: "Time", + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + suffixIcon: Icon( + Icons.access_time, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + // Focus( + // focusNode: focusNodes["_time${index}FocusNode"], + // onFocusChange: (hasFocus) { + // setState(() { + // focusStates["_time${index}Focused"] = hasFocus; + // }); + // }, + // child: GestureDetector( + // // + // onTap: () { + // // Request focus when user taps + // focusNodes["_time${index}FocusNode"]?.requestFocus(); + // }, + ), + ), + ), + if (errorMessages["time_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["time_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (selectedTripType == "Multitrip") + Container( + // color: Colors.blueGrey, + // padding: const EdgeInsets.only(top: 50, bottom: 50), + child: IconButton( + onPressed: () { + removeTrip(index); + }, + icon: Icon(Icons.close, color: Colors.redAccent, size: 20), + ), + ), + ] + : [ + // For mobile, wrap inside a card with padding and grey background + Card( + elevation: 1, + margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + color: const Color(0xFFF5F5F5), // Light grey + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "From*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // isFocused: _fromFocus, + // isFocused: focusStates["_from${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + // isFocused: focusStates["_from${fieldIndex}Focused"] ?? false, + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: + isCountryLoading + ? Center(child: CircularProgressIndicator()) + : Focus( + focusNode: + focusNodes["_from${index}FocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["_from${index}Focused"] = + hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_from${index}FocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch( + enabled: + !(selectedTripType == "Roundtrip" && + index == 2), + selectedItem: + selectedFrom[index] != null + ? countryMap[selectedFrom[index]] + : null, + items: countryMap.values.toList(), + // asyncItems: (String filter) async { + // final allItems = countryMap.values.toSet().toList(); + // print("Original items: ${allItems.length}"); + // final filtered = filterAndSortCountryList(allItems, filter); + // // print("Filtered items: ${filtered.length} -> $filtered"); + // return filtered; + // }, + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 220, + ), + showSearchBox: + true, // Enables search functionality + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search...", + contentPadding: + EdgeInsets.symmetric( + horizontal: 10, + vertical: 1, + ), + ), + style: TextStyle(fontSize: 12), + ), + menuProps: MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: ( + context, + item, + isSelected, + ) { + final parts = item.split('\n'); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 + ? parts[1] + : ''; + + // Extract city and code from "City (CODE)" + final cityMatch = RegExp( + r'^(.*)\s+\(([^)]+)\)$', + ).firstMatch(cityAndCode); + final city = + cityMatch?.group(1) ?? ''; + final code = + cityMatch?.group(2) ?? ''; + + return Padding( + padding: + const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + city, + style: const TextStyle( + fontSize: 12, + fontWeight: + FontWeight.bold, + ), + ), + Text( + code, + style: const TextStyle( + fontSize: 12, + fontWeight: + FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 1), + Text( + airport, + style: const TextStyle( + fontSize: 11, + color: Colors.grey, + overflow: + TextOverflow.ellipsis, + ), + ), + ], + ), + ); + }, + + // itemBuilder: + // (context, item, isSelected) => Padding( + // padding: const EdgeInsets.symmetric( + // horizontal: 8.0, + // vertical: 6.0, + // ), + // child: Text( + // item, + // style: TextStyle( + // fontSize: 13, + // ), // 👈 Set your desired text size here + // ), + // ), ), + // items: countryMap.values.toList(), + // filterFn: (item, filter) { + // final lowerFilter = filter.toLowerCase(); + // + // final parts = item.split('\n'); + // final cityAndCode = parts[0]; + // final airport = parts.length > 1 ? parts[1].toLowerCase() : ''; + // + // // Extract city and code from "City (CODE)" + // final cityMatch = RegExp(r'^(.*)\s+\(([^)]+)\)$').firstMatch(cityAndCode); + // final city = cityMatch?.group(1)?.toLowerCase() ?? ''; + // final code = cityMatch?.group(2)?.toLowerCase() ?? ''; + // + // // Priority: Code > City > Airport + // return code.contains(lowerFilter) || + // city.contains(lowerFilter) || + // airport.contains(lowerFilter); + // }, + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: + BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_from${index}Focused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_from${index}Focused"] ?? + false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: + EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + dropdownBuilder: ( + context, + selectedItem, + ) { + if (selectedItem == null) { + return Align( + alignment: Alignment.centerLeft, + child: const Text( + "Select", + style: TextStyle(fontSize: 12), + ), + ); + } + + final parts = selectedItem.split( + '\n', + ); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 ? parts[1] : ''; + + return Align( + alignment: Alignment.centerLeft, + child: Text( + cityAndCode ?? "Select", + style: const TextStyle( + fontSize: 12, + ), + ), + ); + }, + + // dropdownBuilder: + // (context, selectedItem) => Align( + // alignment: Alignment.centerLeft, + // child: Text( + // selectedItem ?? "Select", + // style: TextStyle(fontSize: 12), + // ), + // ), + onChanged: (String? newValue) { + setState(() { + errorMessages.remove( + "from_place_$index", + ); + // selectedFrom[index] = countryMap.entries + // .firstWhere((entry) => entry.value == newValue) + // .key; + + selectedFrom[index] = + countryMap.entries + .firstWhere( + (entry) => + entry.value == + newValue, + ) + .key; + if (selectedTripType == + "Roundtrip") { + print( + 'rounfTo${selectedFrom[index]}', + ); + // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; + selectedTo[2] = + selectedFrom[index]!; + } + }); + }, ), ), ), - // Focus( - // focusNode: focusNodes["_time${index}FocusNode"], - // onFocusChange: (hasFocus) { - // setState(() { - // focusStates["_time${index}Focused"] = hasFocus; - // }); - // }, - // child: GestureDetector( - // // - // onTap: () { - // // Request focus when user taps - // focusNodes["_time${index}FocusNode"]?.requestFocus(); - // }, + ), + + // child: SizedBox( + // height: 40, + // child: TextField( + // // focusNode: _fromFocusNode, + // focusNode: focusNodes["_from${index}FocusNode"], + // controller: textControllers["_from${index}Controller"], + // style: const TextStyle(fontSize: 12), + // decoration: const InputDecoration( + // labelText: "From", + // labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + // floatingLabelBehavior: FloatingLabelBehavior.never, + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(vertical: 16), + // ), + // ), + // ), + ), + if (errorMessages["from_place_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["from_place_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) SizedBox(width: 20) else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "To*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // isFocused: focusStates["_to${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + isDesktop: isDesktop, + child: SizedBox( + height: 40, + child: + isCountryLoading + ? Center(child: CircularProgressIndicator()) + : Focus( + focusNode: + focusNodes["_to${index}FocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["_to${index}Focused"] = + hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_to${index}FocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch( + enabled: + !(selectedTripType == "Roundtrip" && + index == 2), + selectedItem: + selectedTo[index] != null + ? countryMap[selectedTo[index]] + : null, + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 220, + ), + showSearchBox: + true, // Enables search functionality + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search...", + contentPadding: + EdgeInsets.symmetric( + horizontal: 10, + vertical: 1, + ), + ), + style: TextStyle(fontSize: 12), + ), + menuProps: MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: ( + context, + item, + isSelected, + ) { + final parts = item.split('\n'); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 + ? parts[1] + : ''; + + // Extract city and code from "City (CODE)" + final cityMatch = RegExp( + r'^(.*)\s+\(([^)]+)\)$', + ).firstMatch(cityAndCode); + final city = + cityMatch?.group(1) ?? ''; + final code = + cityMatch?.group(2) ?? ''; + + return Padding( + padding: + const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 6.0, + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + city, + style: const TextStyle( + fontSize: 12, + fontWeight: + FontWeight.bold, + ), + ), + Text( + code, + style: const TextStyle( + fontSize: 12, + fontWeight: + FontWeight.bold, + ), + ), + ], + ), + const SizedBox(height: 1), + Text( + airport, + style: const TextStyle( + fontSize: 11, + color: Colors.grey, + overflow: + TextOverflow.ellipsis, + ), + ), + ], + ), + ); + }, + // itemBuilder: + // (context, item, isSelected) => Padding( + // padding: const EdgeInsets.symmetric( + // horizontal: 8.0, + // vertical: 6.0, + // ), + // child: Text( + // item, + // style: TextStyle( + // fontSize: 13, + // ), // 👈 Set your desired text size here + // ), + // ), + ), + items: countryMap.values.toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: + BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_to${index}Focused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_to${index}Focused"] ?? + false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: + EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + + // dropdownBuilder: + // (context, selectedItem) => Align( + // alignment: Alignment.centerLeft, + // child: Text( + // selectedItem ?? "Select Country", + // style: TextStyle(fontSize: 12), + // ), + // ), + dropdownBuilder: ( + context, + selectedItem, + ) { + if (selectedItem == null) { + return Align( + alignment: Alignment.centerLeft, + child: const Text( + "Select", + style: TextStyle(fontSize: 12), + ), + ); + } + + final parts = selectedItem.split( + '\n', + ); + final cityAndCode = parts[0]; + final airport = + parts.length > 1 ? parts[1] : ''; + + return Align( + alignment: Alignment.centerLeft, + child: Text( + cityAndCode ?? "Select", + style: const TextStyle( + fontSize: 12, + ), + ), + ); + }, + onChanged: (String? newValue) { + setState(() { + errorMessages.remove( + "to_place_$index", + ); + selectedTo[index] = + countryMap.entries + .firstWhere( + (entry) => + entry.value == + newValue, + ) + .key; + + print(selectedTo[index]); + + if (selectedTripType == + "Roundtrip") { + print( + 'rounfTo${selectedTo[index]}', + ); + // textControllers["_to${index+1}Controller"]?.text = selectedFrom[index]!; + selectedFrom[2] = + selectedTo[index]!; + } + }); + }, + ), + ), + ), + ), + ), + if (errorMessages["to_place_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["to_place_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Class *", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // isFocused: focusStates["_class${index}Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + isDesktop: isDesktop, + child: SizedBox( + height: 40, + width: double.infinity, + child: Focus( + focusNode: focusNodes["_class${index}FocusNode"], + + onFocusChange: (hasFocus) { + setState(() { + focusStates["_class${index}Focused"] = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_class${index}FocusNode"] + ?.requestFocus(); + }, + child: DropdownSearch>( + items: purposeList.cast>(), + key: + selectedClasses[index] == null + ? UniqueKey() + : ValueKey(selectedClasses[index]), + // selectedItem: purposeList.firstWhere( + // (item) => item['dropdown_key'] == selectedClasses[index], + // orElse: () => {}, + // ), + selectedItem: + selectedClasses[index] != null + ? purposeList.firstWhere( + (item) => + item['dropdown_key'] == + selectedClasses[index], + orElse: () => {}, + ) + : null, + itemAsString: + (item) => item['dropdown_value'] ?? '', + popupProps: PopupProps.menu( + showSearchBox: false, + fit: FlexFit.loose, + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: (context, item, isSelected) { + final bool isNotAllowed = + item['is_allowed'] == 'No'; + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, + ), + child: Text( + item['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: + isNotAllowed + ? Colors.redAccent + : Colors.black, + ), + ), + ); + }, + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_class${index}Focused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_class${index}Focused"] ?? + false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || + selectedItem.isEmpty) { + return Text( + "Select Class", + style: GoogleFonts.poppins( + color: Colors.grey, + fontSize: 13, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ); + }, + onChanged: + purposeList.isNotEmpty + ? ( + Map? newValue, + ) async { + // if (newValue != null && + // newValue['is_allowed'] == 'No') { + // print('not allowed'); + // + // exceptionalClass[index] = "1"; + // } else if (newValue != null && + // newValue['is_allowed'] == 'yes') { + // print('not allowed'); + // + // exceptionalClass[index] = "0"; + // } + // + // setState(() { + // selectedClasses[index] = + // newValue?['dropdown_key']; + // print( + // "Selected Class: ${selectedClasses[index]}", + // ); + // }); + + if (newValue != null && + newValue['is_allowed'] == 'No') { + final confirm = + await showNotAllowedDialog( + context, + message: + "You are not entitled for this service. If you wish to continue with this service, you may require another approval.", + ); + + if (confirm) { + setState(() { + exceptionalClass[index] = "1"; + selectedClasses[index] = + newValue['dropdown_key']; + }); + print( + "Selected Purpose: ${selectedClasses[index]}", + ); + } else { + setState(() { + exceptionalClass[index] = "0"; + selectedClasses[index] = + null; // ❌ Clear selection if user cancels + }); + print( + "selectedItem resolved to: ${selectedClasses[index]}", + ); + } + + return; + } else if (newValue != null && + newValue['is_allowed'] == 'yes') { + setState(() { + exceptionalClass[index] = "0"; + selectedClasses[index] = + newValue?['dropdown_key']; + print( + "Selected Purpose: ${selectedClasses[index]}", + ); + }); + } + } + : null, + ), + ), + ), + ), + ), + if (errorMessages["class_$index"] != null) + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + errorMessages["class_$index"]!, + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.red, + ), + ), + ), + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Date*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + isFocused: focusStates["_date${index}Focused"] ?? false, + + isDesktop: isDesktop, + width: + isDesktop + ? MediaQuery.of(context).size.width * 0.11 + : null, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () { + focusNodes["_date${index}FocusNode"] + ?.requestFocus(); + _selectCheckOutDate(context); + }, + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["_date${index}FocusNode"], + // controller: _dateController, + controller: + textControllers["_date${index}Controller"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + labelText: "Select Date", + labelStyle: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: + FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + vertical: 16, + ), + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // borderSide: BorderSide( + // color: + // (focusStates["_date${index}Focused"] ?? false) + // ? layoutColor! + // : Colors.white, + // width: 0.5, + // ), + // ), + // enabledBorder: OutlineInputBorder( + // borderSide: BorderSide( + // color: + // (focusStates["_date${index}Focused"] ?? false) + // ? layoutColor + // : Colors.white, + // // : const Color(0xFFD6D5E6), + // width: 0.5, + // // const Color(0xFFD6D5E6), + // ), + // ), + // focusedBorder: OutlineInputBorder( + // borderSide: BorderSide(color: layoutColor, width: 1), + // ), + // contentPadding: const EdgeInsets.symmetric( + // horizontal: 10, + // vertical: 5, + // ), + suffixIcon: const Icon( + Icons.calendar_today, + size: 16, + color: Colors.grey, + ), ), ), ), - if (errorMessages["time_$index"] != null) ...[ - SizedBox(height: 5), // Space before error message - Text( - errorMessages["time_$index"]!, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ], - ], + ), ), - if (selectedTripType == "Multitrip") - if(multiTripRowCount > 1) - Padding( + ), + if (errorMessages["date_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["date_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (isDesktop) Spacer() else SizedBox(height: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Time*", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + isFocused: focusStates["_time${index}Focused"] ?? false, + isDesktop: isDesktop, + width: + isDesktop + ? MediaQuery.of(context).size.width * 0.1 + : null, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: () { + focusNodes["_time${index}FocusNode"] + ?.requestFocus(); + textControllers["_time${index}Controller"]?.text = + ""; + _clearError("time_$index"); + // validateTimeDifference(index); + // _selectCheckOutTime(context); + + _selectCheckOutTime(context, index, () { + validateTimeDifference(index); + setState( + () {}, + ); // ✅ Force rebuild to show the error immediately + }); + }, + + child: AbsorbPointer( + child: TextField( + focusNode: focusNodes["_time${index}FocusNode"], + // controller: _timeController, + controller: + textControllers["_time${index}Controller"], + readOnly: true, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + labelText: "Time", + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + floatingLabelBehavior: + FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + vertical: 16, + ), + suffixIcon: Icon( + Icons.access_time, + size: 16, + color: Colors.grey, + ), + ), + ), + ), + // Focus( + // focusNode: focusNodes["_time${index}FocusNode"], + // onFocusChange: (hasFocus) { + // setState(() { + // focusStates["_time${index}Focused"] = hasFocus; + // }); + // }, + // child: GestureDetector( + // // + // onTap: () { + // // Request focus when user taps + // focusNodes["_time${index}FocusNode"]?.requestFocus(); + // }, + ), + ), + ), + if (errorMessages["time_$index"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["time_$index"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + if (selectedTripType == "Multitrip") + if (multiTripRowCount > 1) + Padding( padding: const EdgeInsets.only(top: 10), child: SizedBox( width: double.infinity, // ensure full width child: ElevatedButton( style: ElevatedButton.styleFrom( - minimumSize: const Size.fromHeight(48), // set height + minimumSize: const Size.fromHeight( + 48, + ), // set height backgroundColor: Colors.red, foregroundColor: Colors.white, shape: RoundedRectangleBorder( @@ -3425,21 +3558,21 @@ class FlightScreenState extends State { ), ), ), - // Container( - // // color: Colors.blueGrey, - // // padding: const EdgeInsets.only(top: 50, bottom: 50), - // child: IconButton( - // onPressed: () { - // removeTrip(index); - // }, - // icon: Icon(Icons.close, color: Colors.redAccent, size: 20), - // ), - // ), - ], - ), + // Container( + // // color: Colors.blueGrey, + // // padding: const EdgeInsets.only(top: 50, bottom: 50), + // child: IconButton( + // onPressed: () { + // removeTrip(index); + // }, + // icon: Icon(Icons.close, color: Colors.redAccent, size: 20), + // ), + // ), + ], ), ), - ]; + ), + ]; } List _buildThirdRow(bool isDesktop) { @@ -3471,192 +3604,350 @@ class FlightScreenState extends State { ), ); } - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Visa Required", - // style: GoogleFonts.poppins( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // color: Color(0xFF575A74), - // ), - // ), - // SizedBox(height: 5), - // CustomTextFieldItnerarySubWrapper( - // // isFocused: _tripTypeFocused, - // isFocused: focusStates["_visa1Focused"] ?? false, - // isDesktop: isDesktop, - // // width: isDesktop - // // ? MediaQuery.of(context).size.width * 0.34 - // // : MediaQuery.of(context).size.width * 0.66, - // child: SizedBox( - // height: 40, - // child: DropdownButtonFormField( - // // focusNode: _tripTypeFocusNode, // Assign the correct focus node - // focusNode: focusNodes["_visa1FocusNode"], - // value: selectedvisa_available, - // style: TextStyle(fontSize: 12), - // decoration: InputDecoration( - // border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric( - // horizontal: 10, - // ), // Proper padding - // ), - // onChanged: - // visa_available.isNotEmpty - // ? (newValue) { - // setState(() { - // selectedvisa_available = newValue; - // // selectedTripType = "Oneway"; - // // Reset `multiTripRowCount` when switching away from Multitrip - // }); - // print( - // "Updating form data: Flight -> trip_type -> $selectedvisa_available", - // ); - // - // // _initializeRows(); - // } - // : null, - // - // items: dropdownItems, - // ), - // ), - // ), - // ], - // ), - //********// - return isDesktop - ? [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Visa Required", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), + + return isDesktop + ? [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Visa Required", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // use same wrapper as class + // isFocused: focusStates["_visa1Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + isDesktop: isDesktop, + child: SizedBox( + height: 35, + width: double.infinity, + child: Focus( + focusNode: focusNodes["_visa1FocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["_visa1Focused"] = hasFocus; + }); + }, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_visa1FocusNode"]?.requestFocus(); + }, + child: DropdownSearch>( + items: visa_available.cast>(), + selectedItem: visa_available.firstWhere( + (item) => + item['dropdown_key'] == selectedvisa_available, + orElse: () => {}, + ), + itemAsString: (item) => item['dropdown_value'] ?? '', + popupProps: PopupProps.menu( + showSearchBox: false, + fit: FlexFit.loose, + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: (context, item, isSelected) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, + ), + child: Text( + item['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), + ); + }, + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_visa1Focused"] ?? false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_visa1Focused"] ?? false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || selectedItem.isEmpty) { + return Text( + "Select Option", + style: GoogleFonts.poppins( + color: Colors.grey, + fontSize: 13, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ); + }, + onChanged: + visa_available.isNotEmpty + ? (Map? newValue) { + setState(() { + selectedvisa_available = + newValue?['dropdown_key']; + print( + "Selected Visa: $selectedvisa_available", + ); + }); + } + : null, ), ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // use same wrapper as class - // isFocused: focusStates["_visa1Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - isDesktop: isDesktop, - child: SizedBox( - height: 35, - width: double.infinity, - child: Focus( - focusNode: focusNodes["_visa1FocusNode"], - onFocusChange: (hasFocus) { - setState(() { - focusStates["_visa1Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_visa1FocusNode"]?.requestFocus(); + ), + ), + ), + ], + ), + if (isDesktop) SizedBox(width: 20), + SizedBox(height: 5), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Comments", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + isFocused: focusStates["_comments1Focused"] ?? false, + isDesktop: isDesktop, + width: + isDesktop ? MediaQuery.of(context).size.width * 0.32 : null, + child: TextField( + focusNode: focusNodes["_comments1FocusNode"], + // controller: _commentsController, + controller: textControllers["_comments1Controller"], + // maxLines: 6, + // keyboardType: TextInputType.multiline, + style: TextStyle(fontSize: 12), + decoration: InputDecoration( + labelText: "Comments", + labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(vertical: 1), + ), + ), + ), + ], + ), + if (isDesktop) Spacer(), + SizedBox(height: 5), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: _handleAction(isDesktop), + ), + ], + ), + ] + : [ + Card( + elevation: 1, + margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + color: const Color(0xFFF5F5F5), // Light grey + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Visa Required", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), + ), + SizedBox(height: 5), + CustomTextFieldItnerarySubWrapper( + // use same wrapper as class + // isFocused: focusStates["_visa1Focused"] ?? false, + isFocused: false, + padding: const EdgeInsets.symmetric(horizontal: 0), + isDesktop: isDesktop, + child: SizedBox( + height: 35, + width: double.infinity, + child: Focus( + focusNode: focusNodes["_visa1FocusNode"], + onFocusChange: (hasFocus) { + setState(() { + focusStates["_visa1Focused"] = hasFocus; + }); }, - child: DropdownSearch>( - items: visa_available.cast>(), - selectedItem: visa_available.firstWhere( - (item) => item['dropdown_key'] == selectedvisa_available, - orElse: () => {}, - ), - itemAsString: (item) => item['dropdown_value'] ?? '', - popupProps: PopupProps.menu( - showSearchBox: false, - fit: FlexFit.loose, - menuProps: const MenuProps(backgroundColor: Colors.white), - itemBuilder: (context, item, isSelected) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 8, - ), - child: Text( - item['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, + child: GestureDetector( + // + onTap: () { + // Request focus when user taps + focusNodes["_visa1FocusNode"]?.requestFocus(); + }, + child: DropdownSearch>( + items: + visa_available.cast>(), + selectedItem: visa_available.firstWhere( + (item) => + item['dropdown_key'] == + selectedvisa_available, + orElse: () => {}, + ), + itemAsString: + (item) => item['dropdown_value'] ?? '', + popupProps: PopupProps.menu( + showSearchBox: false, + fit: FlexFit.loose, + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: (context, item, isSelected) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, ), + child: Text( + item['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), + ); + }, + ), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (focusStates["_visa1Focused"] ?? + false) + ? layoutColor! + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (focusStates["_visa1Focused"] ?? + false) + ? layoutColor + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: layoutColor, + width: 1, + ), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + ), + ), + dropdownBuilder: (context, selectedItem) { + if (selectedItem == null || + selectedItem.isEmpty) { + return Text( + "Select Option", + style: GoogleFonts.poppins( + color: Colors.grey, + fontSize: 13, + ), + ); + } + return Text( + selectedItem['dropdown_value'] ?? '', + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, ), ); }, + onChanged: + visa_available.isNotEmpty + ? (Map? newValue) { + setState(() { + selectedvisa_available = + newValue?['dropdown_key']; + print( + "Selected Visa: $selectedvisa_available", + ); + }); + } + : null, ), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - // border: InputBorder.none, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_visa1Focused"] ?? false) - ? layoutColor! - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_visa1Focused"] ?? false) - ? layoutColor - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: layoutColor, width: 1), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - ), - ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Option", - style: GoogleFonts.poppins( - color: Colors.grey, - fontSize: 13, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ); - }, - onChanged: - visa_available.isNotEmpty - ? (Map? newValue) { - setState(() { - selectedvisa_available = - newValue?['dropdown_key']; - print("Selected Visa: $selectedvisa_available"); - }); - } - : null, ), ), ), ), - ), - ], - ), + ], + ), if (isDesktop) SizedBox(width: 20), SizedBox(height: 5), Column( @@ -3674,7 +3965,10 @@ class FlightScreenState extends State { CustomTextFieldItnerarySubWrapper( isFocused: focusStates["_comments1Focused"] ?? false, isDesktop: isDesktop, - width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null, + width: + isDesktop + ? MediaQuery.of(context).size.width * 0.32 + : null, child: TextField( focusNode: focusNodes["_comments1FocusNode"], // controller: _commentsController, @@ -3684,7 +3978,10 @@ class FlightScreenState extends State { style: TextStyle(fontSize: 12), decoration: InputDecoration( labelText: "Comments", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: TextStyle( + fontSize: 12, + color: Colors.grey, + ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, // contentPadding: EdgeInsets.symmetric(vertical: 1), @@ -3693,208 +3990,21 @@ class FlightScreenState extends State { ), ], ), - if (isDesktop) Spacer(), - SizedBox(height: 5), - Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: _handleAction(isDesktop), - ), - ], - ), - ] - : [ - Card( - elevation: 1, - margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), - color: const Color(0xFFF5F5F5), // Light grey - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Visa Required", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - // use same wrapper as class - // isFocused: focusStates["_visa1Focused"] ?? false, - isFocused: false, - padding: const EdgeInsets.symmetric(horizontal: 0), - isDesktop: isDesktop, - child: SizedBox( - height: 35, - width: double.infinity, - child: Focus( - focusNode: focusNodes["_visa1FocusNode"], - onFocusChange: (hasFocus) { - setState(() { - focusStates["_visa1Focused"] = hasFocus; - }); - }, - child: GestureDetector( - // - onTap: () { - // Request focus when user taps - focusNodes["_visa1FocusNode"]?.requestFocus(); - }, - child: DropdownSearch>( - items: visa_available.cast>(), - selectedItem: visa_available.firstWhere( - (item) => item['dropdown_key'] == selectedvisa_available, - orElse: () => {}, - ), - itemAsString: (item) => item['dropdown_value'] ?? '', - popupProps: PopupProps.menu( - showSearchBox: false, - fit: FlexFit.loose, - menuProps: const MenuProps(backgroundColor: Colors.white), - itemBuilder: (context, item, isSelected) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 8, - ), - child: Text( - item['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ), - ); - }, - ), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - // border: InputBorder.none, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (focusStates["_visa1Focused"] ?? false) - ? layoutColor! - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (focusStates["_visa1Focused"] ?? false) - ? layoutColor - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: layoutColor, width: 1), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - ), - ), - dropdownBuilder: (context, selectedItem) { - if (selectedItem == null || selectedItem.isEmpty) { - return Text( - "Select Option", - style: GoogleFonts.poppins( - color: Colors.grey, - fontSize: 13, - ), - ); - } - return Text( - selectedItem['dropdown_value'] ?? '', - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ); - }, - onChanged: - visa_available.isNotEmpty - ? (Map? newValue) { - setState(() { - selectedvisa_available = - newValue?['dropdown_key']; - print("Selected Visa: $selectedvisa_available"); - }); - } - : null, - ), - ), - ), - ), - ), - ], - ), - if (isDesktop) SizedBox(width: 20), - SizedBox(height: 5), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Comments", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74), - ), - ), - SizedBox(height: 5), - CustomTextFieldItnerarySubWrapper( - isFocused: focusStates["_comments1Focused"] ?? false, - isDesktop: isDesktop, - width: isDesktop ? MediaQuery.of(context).size.width * 0.32 : null, - child: TextField( - focusNode: focusNodes["_comments1FocusNode"], - // controller: _commentsController, - controller: textControllers["_comments1Controller"], - // maxLines: 6, - // keyboardType: TextInputType.multiline, - style: TextStyle(fontSize: 12), - decoration: InputDecoration( - labelText: "Comments", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric(vertical: 1), - ), - ), - ), - ], - ), - ], - ), - ), + ], ), - if (isDesktop) Spacer(), - SizedBox(height: 10), - Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: _handleAction(isDesktop), ), - ], - ), - ]; + ), + if (isDesktop) Spacer(), + SizedBox(height: 10), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: _handleAction(isDesktop), + ), + ], + ), + ]; } List _buildvisa(bool isDesktop) { diff --git a/lib/Screens/itnerary_list/accomodation_list.dart b/lib/Screens/itnerary_list/accomodation_list.dart index 4eb8b3b..03d8aa4 100644 --- a/lib/Screens/itnerary_list/accomodation_list.dart +++ b/lib/Screens/itnerary_list/accomodation_list.dart @@ -2,11 +2,12 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; -class AccomodationListWidget extends StatelessWidget { +import '../../utils/auth_utils.dart'; + +class AccomodationListWidget extends StatefulWidget { final List> accommodationList; final Function(bool, Map, String) onOpen; final Function(Map) onDeleteAccommodation; - final Function(String, bool) onAddNew; final bool isViewMode; @@ -19,12 +20,57 @@ class AccomodationListWidget extends StatelessWidget { required this.isViewMode, }); + @override + State createState() => _AccomodationListWidgetState(); +} + +class _AccomodationListWidgetState extends State { + Color? layoutColor; + Color? secondColor; + Color? thridColor; + + @override + void initState() { + super.initState(); + loadInitialData(); + } + + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + String? secondString = await getSecondaryColor(); + String? thridString = await getTernaryColor(); + + // String? bodyStringColor = await getBodyColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + + secondColor = + layoutString != null + ? Color(int.parse(secondString!)) + : Colors.orange; + + thridColor = + layoutString != null + ? Color(int.parse(thridString!)) + : Colors.orangeAccent; + // bodyColor = + // bodyStringColor != null + // ? Color(int.parse(bodyStringColor)) + // : Colors.white; + }); + } + @override Widget build(BuildContext context) { final isDesktop = MediaQuery.of(context).size.width > 1024; return Padding( - padding: const EdgeInsets.all(16.0), + padding: + isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0), child: Container( margin: const EdgeInsets.only(top: 16.0), child: Column( @@ -34,7 +80,7 @@ class AccomodationListWidget extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if ((!isDesktop) && accommodationList.isNotEmpty) + if ((!isDesktop) && widget.accommodationList.isNotEmpty) Text( " ", style: const TextStyle( @@ -44,17 +90,19 @@ class AccomodationListWidget extends StatelessWidget { ), MouseRegion( - cursor: isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + cursor: + widget.isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: GestureDetector( - onTap: isViewMode - ? null - : () { - print("New data"); - onAddNew("Accomodation", true); - }, + onTap: + widget.isViewMode + ? null + : () { + print("New data"); + widget.onAddNew("Accomodation", true); + }, child: Row( mainAxisSize: MainAxisSize.min, // Ensures content fits nicely @@ -68,7 +116,7 @@ class AccomodationListWidget extends StatelessWidget { Icons.add_circle_sharp, size: 30, color: Color(0xFF114D8B), - ) + ), // Container( // decoration: BoxDecoration( // shape: BoxShape.circle, @@ -147,9 +195,9 @@ class AccomodationListWidget extends StatelessWidget { ], ), const SizedBox(height: 16), - // Scroll behavior based on device - _buildData(context, isDesktop) + // Scroll behavior based on device + _buildData(context, isDesktop), ], ), ), @@ -158,7 +206,9 @@ class AccomodationListWidget extends StatelessWidget { Widget _buildData(BuildContext context, bool isDesktop) { List> filteredList = - accommodationList.where((item) => item["is_active"] == "1").toList(); + widget.accommodationList + .where((item) => item["is_active"] == "1") + .toList(); print("filteredList- $filteredList"); // String formatDate(String dateString) { @@ -191,8 +241,11 @@ class AccomodationListWidget extends StatelessWidget { if (hour == 24 && minute == 0) { // 24:00 is treated as 00:00 on the next day - dateTime = DateTime(now.year, now.month, now.day) - .add(const Duration(days: 1)); + dateTime = DateTime( + now.year, + now.month, + now.day, + ).add(const Duration(days: 1)); } else { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { throw FormatException("Invalid hour or minute"); @@ -235,14 +288,18 @@ class AccomodationListWidget extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), // color: Colors.orange.shade50, - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.black12, - blurRadius: 3, - offset: Offset(0, 1), - ), - ], + color: isDesktop ? Colors.white : thridColor, + // color: Colors.white, + boxShadow: + isDesktop + ? [ + BoxShadow( + color: Colors.black12, + blurRadius: 3, + offset: Offset(0, 1), + ), + ] + : [], border: Border( top: BorderSide( color: Colors.white70, // Change color to match your theme @@ -251,7 +308,7 @@ class AccomodationListWidget extends StatelessWidget { ), ), child: Padding( - padding: EdgeInsets.all(12), + padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -261,26 +318,28 @@ class AccomodationListWidget extends StatelessWidget { Text( item["hotel_name"]!, style: GoogleFonts.poppins( - fontSize: 14, - fontWeight: FontWeight.w800, - color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74),) + fontSize: 14, + fontWeight: + isDesktop ? FontWeight.w800 : FontWeight.w500, + color: !isDesktop ? Colors.black : Color(0xFF575A74), + ), ), Spacer(), GestureDetector( - onTap: () => onOpen(true, item, "Accomodation"), + onTap: () => widget.onOpen(true, item, "Accomodation"), child: Tooltip( message: 'Edit Accomodation Details', child: Image.asset( 'assets/images/IconsImg/edit.png', width: 20, height: 15, - color: Color(0xFF114D8B), + color: isDesktop ? Color(0xFF114D8B) : Colors.black87, ), ), ), SizedBox(width: 10), GestureDetector( - onTap: () => onDeleteAccommodation(item), + onTap: () => widget.onDeleteAccommodation(item), child: Tooltip( message: 'Delete Accommodation Details', child: Image.asset( @@ -293,170 +352,176 @@ class AccomodationListWidget extends StatelessWidget { ), ], ), - Divider( - color: Colors.blueGrey.shade50, - ), + // Divider(color: Colors.blueGrey.shade50), SizedBox(height: 4), isDesktop ? Row( - children: [ - Expanded( - flex: 2, - child: Text( - " DestinationCity", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Check (in) ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Check (out) ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Comments", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - ], - ) + children: [ + Expanded( + flex: 2, + child: Text( + " DestinationCity", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Check (in) ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Check (out) ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Comments", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + ], + ) : SizedBox.shrink(), isDesktop ? Row( - children: [ - Expanded( - flex: 2, - child: Text( - item["destination_city"], - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), + children: [ + Expanded( + flex: 2, + child: Text( + item["destination_city"], + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, ), ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, ), ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, ), ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: _buildComments( - "Comments:", item["comments"] ?? "N/A"), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: _buildComments( + "Comments:", + item["comments"] ?? "N/A", ), - ], - ) - : Column( + ), + ], + ) + : Container( + color: Colors.white, + padding: EdgeInsets.all(8.0), + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Wrap( - spacing: 20, // horizontal space between items - runSpacing: 10, // vertical space between rows - children: [ - _buildInfoColumn("City", item["destination_city"]), - _buildInfoColumn("Check (In)", "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}"), - _buildInfoColumn("Check (Out)", "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}"), - // City - long name handled with flexible space - // Expanded( - // flex: 3, - // child: _buildInfoColumn("City", item["destination_city"]), - // ), - - // SizedBox(width: 8), - - // Check In and Check Out stacked right side - // Expanded( - // flex: 4, - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.end, - // children: [ - // _buildInfoColumn( - // "Check In", - // "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}", - // ), - // SizedBox(height: 6), - // _buildInfoColumn( - // "Check Out", - // "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}", - // ), - // ], - // ), - // ), - ], + _buildRow( + "Destination City", + item["destination_city"], ), - const SizedBox(height: 10), - const Text( - "Comment", - style: TextStyle(fontWeight: FontWeight.w500), + SizedBox(height: 5), + _buildDateTimeRow( + "Check (in)", + formatDate(item["checkin_date"]!), + formatTime(item["checkin_time"]!), ), - const SizedBox(height: 5), - if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty) - Container( - width: double.infinity, - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - border: Border.all(color: Color(0xFF7098DD), width: 1), - borderRadius: BorderRadius.circular(6), - ), - child: Text( - item["comments"], - style: const TextStyle(fontSize: 12), - ), - ) - else - const Text( "N/A", style: TextStyle(fontSize: 12), ), - ], - ) - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // _buildRow("City:", item["destination_city"]), - // SizedBox(width: 10), - // SizedBox(width: 10), - // _buildDateTimeRow( - // "Check-in:", - // formatDate(item["checkin_date"]!), - // item["checkin_time"]!, - // ), - // SizedBox(width: 10), - // _buildRow( - // "Date(out):", formatDate(item["checkout_date"]!)), - // SizedBox(width: 10), - // _buildRow("Comments:", item["comments"] ?? "N/A"), - // ], - // ) + SizedBox(height: 5), + _buildDateTimeRow( + "Check (out)", + formatDate(item["checkout_date"]!), + formatTime(item["checkout_time"]!), + ), + SizedBox(height: 5), + _buildRow("Comments:", item["comments"] ?? "N/A"), + ], + ), + ), + + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Wrap( + // spacing: 20, // horizontal space between items + // runSpacing: 10, // vertical space between rows + // children: [ + // _buildInfoColumn("City", item["destination_city"]), + // _buildInfoColumn("Check (In)", "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}"), + // _buildInfoColumn("Check (Out)", "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}"), + // // City - long name handled with flexible space + // // Expanded( + // // flex: 3, + // // child: _buildInfoColumn("City", item["destination_city"]), + // // ), + // + // // SizedBox(width: 8), + // + // // Check In and Check Out stacked right side + // // Expanded( + // // flex: 4, + // // child: Column( + // // crossAxisAlignment: CrossAxisAlignment.end, + // // children: [ + // // _buildInfoColumn( + // // "Check In", + // // "${formatDate(item["checkin_date"]!)} ${formatTime(item["checkin_time"]!)}", + // // ), + // // SizedBox(height: 6), + // // _buildInfoColumn( + // // "Check Out", + // // "${formatDate(item["checkout_date"]!)} ${formatTime(item["checkout_time"]!)}", + // // ), + // // ], + // // ), + // // ), + // ], + // ), + // const SizedBox(height: 10), + // const Text( + // "Comment", + // style: TextStyle(fontWeight: FontWeight.w500), + // ), + // const SizedBox(height: 5), + // if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty) + // Container( + // width: double.infinity, + // padding: const EdgeInsets.all(8), + // decoration: BoxDecoration( + // border: Border.all(color: Color(0xFF7098DD), width: 1), + // borderRadius: BorderRadius.circular(6), + // ), + // child: Text( + // item["comments"], + // style: const TextStyle(fontSize: 12), + // ), + // ) + // else + // const Text( "N/A", style: TextStyle(fontSize: 12), ), + // ], + // ) ], ), ), @@ -485,31 +550,35 @@ class AccomodationListWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: exceedsLimit - ? Tooltip( - message: wrapText(value, 50), - decoration: BoxDecoration( - color: Colors.grey.shade200, // Black background - borderRadius: BorderRadius.circular(6), - ), - textStyle: - TextStyle(color: Colors.black), // Tooltip text color - padding: EdgeInsets.all(8), - preferBelow: false, - child: Text(value.substring(0, limit) + "...", + child: + exceedsLimit + ? Tooltip( + message: wrapText(value, 50), + decoration: BoxDecoration( + color: Colors.grey.shade200, // Black background + borderRadius: BorderRadius.circular(6), + ), + textStyle: TextStyle( + color: Colors.black, + ), // Tooltip text color + padding: EdgeInsets.all(8), + preferBelow: false, + child: Text( + value.substring(0, limit) + "...", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), - overflow: TextOverflow.ellipsis), - ) - : Text( - value, - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, + overflow: TextOverflow.ellipsis, + ), + ) + : Text( + value, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), ), - ), ), ], ); @@ -531,87 +600,92 @@ class AccomodationListWidget extends StatelessWidget { SizedBox(height: 4), Text( value, - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black87, - ), + style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87), ), ], ); } - // Widget _buildRow(String title, String value) { - // // Define character limits based on title - // Map limits = { - // // "Special Request:": 30, - // "Comments:": 10, - // // Add more keys and limits if needed - // }; - // - // int limit = limits[title] ?? 50; // Default limit if title not found - // bool exceedsLimit = value.length > limit; - // - // String wrapText(String text, int maxLineLength) { - // final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)'); - // return pattern.allMatches(text).map((m) => m.group(0)!).join('\n'); - // } - // - // return Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // title, - // style: GoogleFonts.poppins( - // fontSize: 12, - // ), - // ), - // SizedBox(width: 8), - // Expanded( - // child: exceedsLimit - // ? Tooltip( - // message: wrapText(value, 50), - // decoration: BoxDecoration( - // color: Colors.grey.shade200, // Black background - // borderRadius: BorderRadius.circular(6), - // ), - // textStyle: - // TextStyle(color: Colors.black), // Tooltip text color - // padding: EdgeInsets.all(8), - // preferBelow: false, - // child: Text(value.substring(0, limit) + "...", - // style: TextStyle(fontSize: 12), - // overflow: TextOverflow.ellipsis), - // ) - // : Text( - // value, - // style: TextStyle(fontSize: 12), - // ), - // ), - // ], - // ); - // } + Widget _buildRow(String title, String value) { + // Define character limits based on title + Map limits = { + // "Special Request:": 30, + "Comments:": 10, + // Add more keys and limits if needed + }; - // Widget _buildDateTimeRow(String title, String date, String time) { - // return Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // title, - // style: GoogleFonts.poppins( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // ), - // ), - // SizedBox(width: 8), - // Expanded( - // child: Text( - // "$date, $time", - // style: GoogleFonts.poppins( - // fontSize: 12, - // ), - // ), - // ), - // ], - // ); - // } + int limit = limits[title] ?? 50; // Default limit if title not found + bool exceedsLimit = value.length > limit; + + String wrapText(String text, int maxLineLength) { + final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)'); + return pattern.allMatches(text).map((m) => m.group(0)!).join('\n'); + } + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + + children: [ + SizedBox( + // color: Colors.yellowAccent.shade100, + width: 100, + child: Expanded( + child: Text( + title, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + SizedBox(width: 5), + Expanded(child: Text(value, style: TextStyle(fontSize: 12))), + // Expanded( + // child: + // exceedsLimit + // ? Tooltip( + // message: wrapText(value, 50), + // decoration: BoxDecoration( + // color: Colors.grey.shade200, // Black background + // borderRadius: BorderRadius.circular(6), + // ), + // textStyle: TextStyle( + // color: Colors.black, + // ), // Tooltip text color + // padding: EdgeInsets.all(8), + // preferBelow: false, + // child: Text( + // value.substring(0, limit) + "...", + // style: TextStyle(fontSize: 12), + // overflow: TextOverflow.ellipsis, + // ), + // ) + // : Text(value, style: TextStyle(fontSize: 12)), + // ), + ], + ); + } + + Widget _buildDateTimeRow(String title, String date, String time) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 100, + child: Text( + title, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 5), + Expanded( + child: Text("$date, $time", style: GoogleFonts.poppins(fontSize: 12)), + ), + ], + ); + } } diff --git a/lib/Screens/itnerary_list/flight_list.dart b/lib/Screens/itnerary_list/flight_list.dart index 79d886e..6ee238b 100644 --- a/lib/Screens/itnerary_list/flight_list.dart +++ b/lib/Screens/itnerary_list/flight_list.dart @@ -3,6 +3,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; class FlightListWidget extends StatefulWidget { final bool hasAction; @@ -32,6 +33,9 @@ class FlightListWidget extends StatefulWidget { class _FlightListWidgetState extends State { ApiService apiService = ApiService(); + Color? layoutColor; + Color? secondColor; + Color? thridColor; // late Map countryMap; Map countryMap = {}; @@ -40,6 +44,36 @@ class _FlightListWidgetState extends State { void initState() { super.initState(); loadCountryList(); // Call your method here + loadInitialData(); + } + + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + String? secondString = await getSecondaryColor(); + String? thridString = await getTernaryColor(); + + // String? bodyStringColor = await getBodyColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + + secondColor = + layoutString != null + ? Color(int.parse(secondString!)) + : Colors.orange; + + thridColor = + layoutString != null + ? Color(int.parse(thridString!)) + : Colors.orangeAccent; + // bodyColor = + // bodyStringColor != null + // ? Color(int.parse(bodyStringColor)) + // : Colors.white; + }); } Future loadCountryList() async { @@ -169,7 +203,8 @@ class _FlightListWidgetState extends State { // ); return Padding( - padding: const EdgeInsets.all(16.0), + padding: + isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0), child: Container( margin: const EdgeInsets.only(top: 16.0), child: Column( @@ -192,16 +227,18 @@ class _FlightListWidgetState extends State { // Right side: either "Add" icon or nothing if (widget.flightList.isNotEmpty) MouseRegion( - cursor: widget.isViewMode - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, + cursor: + widget.isViewMode + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, child: GestureDetector( - onTap: widget.isViewMode - ? null - : () { - widget.onAddNew("Flight", true); - print("New data"); - }, + onTap: + widget.isViewMode + ? null + : () { + widget.onAddNew("Flight", true); + print("New data"); + }, child: Icon( Icons.add_circle_sharp, size: 30, @@ -210,7 +247,7 @@ class _FlightListWidgetState extends State { ), ) else if (!isDesktop) - // Centered "No Data Found" message for mobile and empty list + // Centered "No Data Found" message for mobile and empty list Expanded( child: Center( child: Text( @@ -223,8 +260,7 @@ class _FlightListWidgetState extends State { ), ), ), - ) - + ), ], ), const SizedBox(height: 16), @@ -235,7 +271,6 @@ class _FlightListWidgetState extends State { ), ), ); - } Widget _buildData(BuildContext context, bool isDesktop) { @@ -347,22 +382,26 @@ class _FlightListWidgetState extends State { margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), + // color: isDesktop ? Colors.white : Color(0xFFFFF0F5), + color: isDesktop ? Colors.white : thridColor, // color: Colors.orange.shade50, - color: Colors.white, - - boxShadow: [ - BoxShadow( - color: Colors.black12, - blurRadius: 2, - offset: Offset(0, 2), // down - ), - // Top shadow - BoxShadow( - color: Colors.black12, - blurRadius: 0.5, - offset: Offset(0, -1), // up - ), - ], + // color: Colors.white, + boxShadow: + isDesktop + ? [ + BoxShadow( + color: Colors.black12, + blurRadius: 2, + offset: Offset(0, 2), // down + ), + // Top shadow + BoxShadow( + color: Colors.black12, + blurRadius: 0.5, + offset: Offset(0, -1), // up + ), + ] + : [], border: Border( top: BorderSide( color: Colors.white70, // Change color to match your theme @@ -371,49 +410,56 @@ class _FlightListWidgetState extends State { ), ), child: Padding( - padding: EdgeInsets.all(12), + padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Text( - tripTypeName ?? "N/A", - style: GoogleFonts.poppins( - fontSize: 14, - fontWeight: FontWeight.w800, - color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74), - ), - ), - Spacer(), - GestureDetector( - onTap: () => widget.onOpen(true, item, "Flight"), - child: Tooltip( - message: 'Edit Flight Details', - child: Image.asset( - 'assets/images/IconsImg/edit.png', - width: 20, - height: 15, - color: Color(0xFF114D8B), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: Row( + children: [ + Text( + tripTypeName ?? "N/A", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: + isDesktop ? FontWeight.w800 : FontWeight.w500, + color: !isDesktop ? Colors.black : Color(0xFF575A74), + + // Color(0xFF114D8B) ), ), - ), - SizedBox(width: 10), - GestureDetector( - onTap: () => widget.onDeleteFlight(item), - child: Tooltip( - message: 'Delete Flight Details', - child: Image.asset( - 'assets/images/IconsImg/delete.png', - width: 20, - height: 15, - color: Colors.red, + Spacer(), + GestureDetector( + onTap: () => widget.onOpen(true, item, "Flight"), + child: Tooltip( + message: 'Edit Flight Details', + child: Image.asset( + 'assets/images/IconsImg/edit.png', + width: 20, + height: 15, + color: + isDesktop ? Color(0xFF114D8B) : Colors.black87, + ), ), ), - ), - ], + SizedBox(width: 10), + GestureDetector( + onTap: () => widget.onDeleteFlight(item), + child: Tooltip( + message: 'Delete Flight Details', + child: Image.asset( + 'assets/images/IconsImg/delete.png', + width: 20, + height: 15, + color: Colors.red, + ), + ), + ), + ], + ), ), - Divider(color: Colors.blueGrey.shade50), + // Divider(color: Colors.blueGrey.shade50), SizedBox(height: 4), if (isDesktop) Row( @@ -600,10 +646,9 @@ class _FlightListWidgetState extends State { item["trips"] != null && item["trips"].isNotEmpty) ...item["trips"].map((trip) { - String fromPlaceCountry = countryMap[trip["from_place"]?.toString()] ?? - "Unknown Country"; + "Unknown Country"; final parts = fromPlaceCountry.split('\n'); final cityAndCode = parts[0]; @@ -618,7 +663,7 @@ class _FlightListWidgetState extends State { String toPlaceCountry = countryMap[trip["to_place"]?.toString()] ?? - "Unknown Country"; + "Unknown Country"; final toparts = toPlaceCountry.split('\n'); final tocityAndCode = toparts[0]; @@ -631,41 +676,44 @@ class _FlightListWidgetState extends State { final tocity = tocityMatch?.group(1) ?? ''; final tocode = tocityMatch?.group(2) ?? ''; - // return Padding( - // padding: const EdgeInsets.symmetric(vertical: 6.0), - // child: Container( - // decoration: BoxDecoration( - // border: Border.all(color: Colors.grey.shade300), - // borderRadius: BorderRadius.circular(6), - // color: Colors.grey.shade50, - // ), - // padding: const EdgeInsets.all(8), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // _buildKeyValueRow( - // "Class", - // getRequestForClass(trip["class"].toString()) ?? - // "N/A", - // ), - // _buildKeyValueRow( - // "Sector", - // "$fromcity ($fromcode), $fromairport → $tocity ($tocode), $toairport", - // ), - // - // _buildKeyValueRow( - // "Date", - // formatDate(trip["date"] ?? ""), - // ), - // _buildKeyValueRow( - // "Time", - // formatTime(trip["time"] ?? ""), - // ), - // ], - // ), - // ), - // ); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6.0), + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(6), + color: Colors.grey.shade50, + ), + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildKeyValueRow( + "Class", + getRequestForClass(trip["class"].toString()) ?? + "N/A", + ), + _buildKeyValueRow( + "From", + "$fromcity ($fromcode), $fromairport ", + ), + _buildKeyValueRow( + "To", + "$tocity ($tocode), $toairport", + ), + _buildKeyValueRow( + "Date", + formatDate(trip["date"] ?? ""), + ), + _buildKeyValueRow( + "Time", + formatTime(trip["time"] ?? ""), + ), + ], + ), + ), + ); // return Padding( // padding: const EdgeInsets.symmetric(vertical: 6.0), @@ -701,9 +749,13 @@ class _FlightListWidgetState extends State { // ), // ), // const Padding( - // padding: EdgeInsets.symmetric(horizontal: 6), + // padding: EdgeInsets.symmetric( + // horizontal: 6, + // ), // child: Image( - // image: AssetImage('assets/images/IconsImg/Frame.png'), + // image: AssetImage( + // 'assets/images/IconsImg/Frame.png', + // ), // width: 18, // height: 18, // ), @@ -738,68 +790,67 @@ class _FlightListWidgetState extends State { // ), // ); - return Padding( - padding: const EdgeInsets.symmetric(vertical: 6.0), - child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - spacing: 4, - runSpacing: 4, - children: [ - Text( - '${getRequestForClass(trip["class"].toString()) ?? "N/A"} (', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Colors.black87, - ), - ), - Text( - fromcode, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Colors.black87, - ), - ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 4), - child: Image( - image: AssetImage('assets/images/IconsImg/Frame.png'), - width: 18, - height: 18, - ), - ), - Text( - '$tocode)', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Colors.black87, - ), - ), - ], - ), - const SizedBox(height: 6), - Align( - alignment: Alignment.centerRight, - child: Text( - '${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}', - textAlign: TextAlign.right, - style: const TextStyle( - fontSize: 13, - color: Colors.black87, - ), - ), - ), - ], - ), - ), - ); - + // return Padding( + // padding: const EdgeInsets.symmetric(vertical: 6.0), + // child: Container( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Wrap( + // crossAxisAlignment: WrapCrossAlignment.center, + // spacing: 4, + // runSpacing: 4, + // children: [ + // Text( + // '${getRequestForClass(trip["class"].toString()) ?? "N/A"} (', + // style: const TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 14, + // color: Colors.black87, + // ), + // ), + // Text( + // fromcode, + // style: const TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 14, + // color: Colors.black87, + // ), + // ), + // const Padding( + // padding: EdgeInsets.symmetric(horizontal: 4), + // child: Image( + // image: AssetImage('assets/images/IconsImg/Frame.png'), + // width: 18, + // height: 18, + // ), + // ), + // Text( + // '$tocode)', + // style: const TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 14, + // color: Colors.black87, + // ), + // ), + // ], + // ), + // const SizedBox(height: 6), + // Align( + // alignment: Alignment.centerRight, + // child: Text( + // '${formatDate(trip["date"] ?? "")} ${formatTime(trip["time"] ?? "")}', + // textAlign: TextAlign.right, + // style: const TextStyle( + // fontSize: 13, + // color: Colors.black87, + // ), + // ), + // ), + // ], + // ), + // ), + // ); }).toList(), ], ), @@ -816,12 +867,12 @@ class _FlightListWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( - width: 80, // adjust width as needed + width: 70, // adjust width as needed child: Text( - "$key:", + "$key", style: GoogleFonts.poppins( fontSize: 12, - fontWeight: FontWeight.w700, + fontWeight: FontWeight.w600, ), ), ), diff --git a/lib/Screens/itnerary_list/forex_list.dart b/lib/Screens/itnerary_list/forex_list.dart index 97014ec..6662d52 100644 --- a/lib/Screens/itnerary_list/forex_list.dart +++ b/lib/Screens/itnerary_list/forex_list.dart @@ -5,8 +5,9 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; -class ForexListWidget extends StatelessWidget { +class ForexListWidget extends StatefulWidget { final List> forexList; final Function(bool, Map, String) onOpen; final Function(Map) onDeleteForex; @@ -16,15 +17,60 @@ class ForexListWidget extends StatelessWidget { final Function(String, bool) onAddNew; final bool isViewMode; - const ForexListWidget( - {super.key, - required this.forexList, - required this.onOpen, - required this.onDeleteForex, - required this.apiCountryData, - required this.onAddNew, - required this.apiData, - required this.isViewMode}); + const ForexListWidget({ + super.key, + required this.forexList, + required this.onOpen, + required this.onDeleteForex, + required this.apiCountryData, + required this.onAddNew, + required this.apiData, + required this.isViewMode, + }); + + @override + State createState() => _ForexListWidgetState(); +} + +class _ForexListWidgetState extends State { + Color? layoutColor; + Color? secondColor; + Color? thridColor; + + @override + void initState() { + super.initState(); + loadInitialData(); + } + + void loadInitialData() async { + String? layoutString = await getLayoutColor(); + String? secondString = await getSecondaryColor(); + String? thridString = await getTernaryColor(); + + // String? bodyStringColor = await getBodyColor(); + + setState(() { + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; + + secondColor = + layoutString != null + ? Color(int.parse(secondString!)) + : Colors.orange; + + thridColor = + layoutString != null + ? Color(int.parse(thridString!)) + : Colors.orangeAccent; + // bodyColor = + // bodyStringColor != null + // ? Color(int.parse(bodyStringColor)) + // : Colors.white; + }); + } @override Widget build(BuildContext context) { @@ -32,7 +78,8 @@ class ForexListWidget extends StatelessWidget { final ApiService apiService = ApiService(); return Padding( - padding: const EdgeInsets.all(16.0), + padding: + isDesktop ? const EdgeInsets.all(16.0) : const EdgeInsets.all(5.0), child: Container( margin: const EdgeInsets.only(top: 16.0), child: Column( @@ -135,26 +182,23 @@ class ForexListWidget extends StatelessWidget { // ], // ), const SizedBox(height: 16), - // Scroll behavior based on device - _buildData(context, isDesktop) + // Scroll behavior based on device + _buildData(context, isDesktop), ], ), ), ); } - Widget _buildData( - BuildContext context, - bool isDesktop, - ) { + Widget _buildData(BuildContext context, bool isDesktop) { final ApiService apiService = ApiService(); List> filteredList = - forexList.where((item) => item["is_active"] == "1").toList(); + widget.forexList.where((item) => item["is_active"] == "1").toList(); print("filteredList- $filteredList"); - List visatypeList = apiData?['visa_type_of_visa'] ?? []; - List countryList = apiCountryData ?? []; + List visatypeList = widget.apiData?['visa_type_of_visa'] ?? []; + List countryList = widget.apiCountryData ?? []; String getRequestForVisa(String? specialRequestKey) { if (specialRequestKey == null) return "N/A"; @@ -209,8 +253,11 @@ class ForexListWidget extends StatelessWidget { if (hour == 24 && minute == 0) { // 24:00 is treated as 00:00 on the next day - dateTime = DateTime(now.year, now.month, now.day) - .add(const Duration(days: 1)); + dateTime = DateTime( + now.year, + now.month, + now.day, + ).add(const Duration(days: 1)); } else { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { throw FormatException("Invalid hour or minute"); @@ -231,27 +278,34 @@ class ForexListWidget extends StatelessWidget { itemBuilder: (context, index) { final item = filteredList[index]; final double transport = double.tryParse(item["transport"] ?? "0") ?? 0; - final double accommodation = double.tryParse(item["accommodation"] ?? "0") ?? 0; + final double accommodation = + double.tryParse(item["accommodation"] ?? "0") ?? 0; final double telephone = double.tryParse(item["telephone"] ?? "0") ?? 0; - final double perdiemAmount = double.tryParse(item["perdiem_amount"] ?? "0") ?? 0; + final double perdiemAmount = + double.tryParse(item["perdiem_amount"] ?? "0") ?? 0; final double calculatedValue = transport + accommodation + telephone; - final String calculatedOtherExpenses = calculatedValue.toStringAsFixed(0); + final String calculatedOtherExpenses = calculatedValue.toStringAsFixed( + 0, + ); final double finalTotal = calculatedValue + perdiemAmount; - return Container( margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), // color: Colors.orange.shade50, - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.black12, - blurRadius: 3, - offset: Offset(0, 1), - ), - ], + // color: Colors.white, + color: isDesktop ? Colors.white : thridColor, + boxShadow: + isDesktop + ? [ + BoxShadow( + color: Colors.black12, + blurRadius: 3, + offset: Offset(0, 1), + ), + ] + : [], border: Border( top: BorderSide( color: Colors.white70, // Change color to match your theme @@ -260,7 +314,7 @@ class ForexListWidget extends StatelessWidget { ), ), child: Padding( - padding: EdgeInsets.all(12), + padding: isDesktop ? EdgeInsets.all(12) : EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -271,12 +325,12 @@ class ForexListWidget extends StatelessWidget { getRequestForCountry(item["country_code"]!.toString()), style: GoogleFonts.poppins( fontSize: 12, - fontWeight: FontWeight.w700, + fontWeight: FontWeight.w600, ), ), Spacer(), GestureDetector( - onTap: () => onOpen(true, item, "Forex"), + onTap: () => widget.onOpen(true, item, "Forex"), child: Tooltip( message: 'Edit Forex Details', child: Image.asset( @@ -284,7 +338,7 @@ class ForexListWidget extends StatelessWidget { width: 20, height: 15, // color: Color(0xFF114D8B), - color: !isDesktop ? Color(0xFF114D8B) : Color(0xFF575A74) + color: !isDesktop ? Colors.black : Color(0xFF575A74), ), ), ), @@ -303,287 +357,307 @@ class ForexListWidget extends StatelessWidget { // ), item['forex_id'] != null ? IconButton( - icon: Icon(Icons.download, - color: Color(0xFF114D8B), size: 18), - onPressed: () { - print("PDF- ${item['forex_id']}"); - final forexIdString = item['forex_id']; - final id = int.tryParse(forexIdString ?? ''); + icon: Icon( + Icons.download, + color: Color(0xFF114D8B), + size: 18, + ), + onPressed: () { + print("PDF- ${item['forex_id']}"); + final forexIdString = item['forex_id']; + final id = int.tryParse(forexIdString ?? ''); - if (id != null) { - apiService.getForexPdfDownload(id); - } else { - print("Invalid forex_id: $forexIdString"); - } - }, - ) + if (id != null) { + apiService.getForexPdfDownload(id); + } else { + print("Invalid forex_id: $forexIdString"); + } + }, + ) : SizedBox.shrink(), // or Container() ], ), - Divider( - color: Colors.blueGrey.shade50, - ), - SizedBox(height: 4), + Divider(color: Colors.blueGrey.shade50), + // SizedBox(height: 4), isDesktop ? Row( - children: [ - Expanded( - flex: 2, - child: Text( - "Currency", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Duration", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Time Period ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - // Expanded( - // flex: 2, - // child: Text( - // " Total ", - // style: TextStyle( - // fontSize: 11, fontFamily: "Archivo"), - // )), - Expanded( - flex: 2, - child: Text( - " Perdiem ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Others ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Total ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Cash ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Card ", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - Expanded( - flex: 2, - child: Text( - " Comments", - style: GoogleFonts.poppins( - fontSize: 11, - ), - )), - ], - ) + children: [ + Expanded( + flex: 2, + child: Text( + "Currency", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Duration", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Time Period ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + // Expanded( + // flex: 2, + // child: Text( + // " Total ", + // style: TextStyle( + // fontSize: 11, fontFamily: "Archivo"), + // )), + Expanded( + flex: 2, + child: Text( + " Perdiem ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Others ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Total ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Cash ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Card ", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + Expanded( + flex: 2, + child: Text( + " Comments", + style: GoogleFonts.poppins(fontSize: 11), + ), + ), + ], + ) : SizedBox.shrink(), isDesktop ? Row( - children: [ - Expanded( - flex: 2, - child: Text( - item["currency"], - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - item["duration"], - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"]!)}", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "$perdiemAmount", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "$calculatedOtherExpenses", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - "$finalTotal", - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - item["deposit_on_cash"], - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: Text( - item["deposit_on_card"], - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - SizedBox(width: 10), - Expanded( - flex: 2, - child: _buildComments( - "Comments:", item["comments"] ?? "N/A"), - ), - ], - ): Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Top Row (Country, Currency, Total) - Wrap( - spacing: 20, // horizontal space between items - runSpacing: 10, // vertical space between rows - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _infoBlock("Country code", item["country_code"] ?? "N/A"), - _infoBlock("Currency", item["currency"] ?? "N/A"), - _infoBlock("Total Amount", item["total_amount"]?.toString() ?? "0"), + Expanded( + flex: 2, + child: Text( + item["currency"], + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + item["duration"], + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + "${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"]!)}", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + "$perdiemAmount", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + "$calculatedOtherExpenses", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + "$finalTotal", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + item["deposit_on_cash"], + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: Text( + item["deposit_on_card"], + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox(width: 10), + Expanded( + flex: 2, + child: _buildComments( + "Comments:", + item["comments"] ?? "N/A", + ), + ), ], - ), - const SizedBox(height: 12), - - // Second Row (Start Date, End Date, Duration) - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _infoBlock("Start Date", item["start_date"] ?? "N/A"), - _infoBlock("End Date", item["end_date"] ?? "N/A"), - _infoBlock("Duration", item["duration"]?.toString() ?? "N/A"), - ], - ), - const SizedBox(height: 16), - - // Comment label - Text( - "Comment", - style: GoogleFonts.poppins( - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 8), - if (item["comments"] != null && item["comments"].toString().trim().isNotEmpty) - Container( - width: double.infinity, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - border: Border.all(color: const Color(0xFF7098DD), width: 1), - borderRadius: BorderRadius.circular(6), - ), - child: Text( - item["comments"] ?? "N/A", - style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87), - ), ) - else - const Text( "N/A", style: TextStyle(fontSize: 12), ), - ], - ), - // old code - // : Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // _buildRow( - // "Currency:", - // item["currency"], - // ), - // // SizedBox(height: 6), - // _buildRow( - // "Duration:", - // item["duration"], - // ), - // // SizedBox(height: 6), - // _buildRow("StartDate:", item["start_date"]!), - // _buildRow("EndDate:", item["end_date"]!), - // _buildRow("Perdiem:", "$perdiemAmount",), - // _buildRow("Others:", "$calculatedOtherExpenses"), - // _buildRow("Total:", "$finalTotal"), - // _buildRow("Cash:", item["deposit_on_cash"]!), - // _buildRow("Card:", item["deposit_on_card"]!), - // _buildRow("Comments:", item["comments"] ?? "N/A"), - // ], - // ), + : Container( + color: Colors.white, + padding: const EdgeInsets.all(4.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildRow("Currency", item["currency"]), + SizedBox(height: 2), + _buildRow("Duration", item["duration"]), + SizedBox(height: 2), + _buildRow( + "Time Period", + "${formatDate(item["start_date"]!)} - ${formatDate(item["end_date"]!)}", + // "${item["start_date"]!} - ${item["end_date"]!}", + ), + SizedBox(height: 2), + _buildRow("Perdiem", "$perdiemAmount"), + SizedBox(height: 2), + _buildRow("Others", "$calculatedOtherExpenses"), + SizedBox(height: 2), + _buildRow("Total", "$finalTotal"), + SizedBox(height: 2), + _buildRow("Cash", item["deposit_on_cash"]!), + SizedBox(height: 2), + _buildRow("Card", item["deposit_on_card"]!), + SizedBox(height: 2), + _buildRow("Comments", item["comments"] ?? "N/A"), + ], + ), + ), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // // Top Row (Country, Currency, Total) + // Wrap( + // spacing: 20, // horizontal space between items + // runSpacing: 10, // vertical space between rows + // // Row( + // // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // _infoBlock( + // "Country code", + // item["country_code"] ?? "N/A", + // ), + // _infoBlock("Currency", item["currency"] ?? "N/A"), + // _infoBlock( + // "Total Amount", + // item["total_amount"]?.toString() ?? "0", + // ), + // ], + // ), + // const SizedBox(height: 12), + // + // // Second Row (Start Date, End Date, Duration) + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // _infoBlock( + // "Start Date", + // item["start_date"] ?? "N/A", + // ), + // _infoBlock("End Date", item["end_date"] ?? "N/A"), + // _infoBlock( + // "Duration", + // item["duration"]?.toString() ?? "N/A", + // ), + // ], + // ), + // const SizedBox(height: 16), + // + // // Comment label + // Text( + // "Comment", + // style: GoogleFonts.poppins( + // fontSize: 14, + // fontWeight: FontWeight.w600, + // ), + // ), + // const SizedBox(height: 8), + // if (item["comments"] != null && + // item["comments"].toString().trim().isNotEmpty) + // Container( + // width: double.infinity, + // padding: const EdgeInsets.all(12), + // decoration: BoxDecoration( + // border: Border.all( + // color: const Color(0xFF7098DD), + // width: 1, + // ), + // borderRadius: BorderRadius.circular(6), + // ), + // child: Text( + // item["comments"] ?? "N/A", + // style: GoogleFonts.poppins( + // fontSize: 12, + // color: Colors.black87, + // ), + // ), + // ) + // else + // const Text("N/A", style: TextStyle(fontSize: 12)), + // ], + // ), ], ), ), @@ -612,31 +686,35 @@ class ForexListWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: exceedsLimit - ? Tooltip( - message: wrapText(value, 50), - decoration: BoxDecoration( - color: Colors.grey.shade200, // Black background - borderRadius: BorderRadius.circular(6), - ), - textStyle: - TextStyle(color: Colors.black), // Tooltip text color - padding: EdgeInsets.all(8), - preferBelow: false, - child: Text(value.substring(0, limit) + "...", + child: + exceedsLimit + ? Tooltip( + message: wrapText(value, 50), + decoration: BoxDecoration( + color: Colors.grey.shade200, // Black background + borderRadius: BorderRadius.circular(6), + ), + textStyle: TextStyle( + color: Colors.black, + ), // Tooltip text color + padding: EdgeInsets.all(8), + preferBelow: false, + child: Text( + value.substring(0, limit) + "...", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), - overflow: TextOverflow.ellipsis), - ) - : Text( - value, - style: GoogleFonts.poppins( - fontSize: 12, - fontWeight: FontWeight.w600, + overflow: TextOverflow.ellipsis, + ), + ) + : Text( + value, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + ), ), - ), ), ], ); @@ -660,10 +738,7 @@ class ForexListWidget extends StatelessWidget { const SizedBox(height: 4), Text( value, - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black87, - ), + style: GoogleFonts.poppins(fontSize: 12, color: Colors.black87), ), ], ), @@ -671,60 +746,59 @@ class ForexListWidget extends StatelessWidget { ); } - // Widget _buildRow(String title, String value) { - // // Define character limits based on title - // Map limits = { - // // "Special Request:": 30, - // "Comments:": 10, - // // Add more keys and limits if needed - // }; - // - // int limit = limits[title] ?? 50; // Default limit if title not found - // bool exceedsLimit = value.length > limit; - // - // String wrapText(String text, int maxLineLength) { - // final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)'); - // return pattern.allMatches(text).map((m) => m.group(0)!).join('\n'); - // } - // - // return Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // title, - // style: GoogleFonts.poppins( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // ), - // ), - // SizedBox(width: 8), - // Expanded( - // child: exceedsLimit - // ? Tooltip( - // message: wrapText(value, 50), - // decoration: BoxDecoration( - // color: Colors.grey.shade200, // Black background - // borderRadius: BorderRadius.circular(6), - // ), - // textStyle: - // TextStyle(color: Colors.black), // Tooltip text color - // padding: EdgeInsets.all(8), - // preferBelow: false, - // child: Text(value.substring(0, limit) + "...", - // style: GoogleFonts.poppins( - // fontSize: 12, - // ), - // overflow: TextOverflow.ellipsis), - // ) - // : Text( - // value, - // style: GoogleFonts.poppins( - // fontSize: 12, - // ), - // ), - // ), - // ], - // ); - // } + Widget _buildRow(String title, String value) { + // Define character limits based on title + Map limits = { + // "Special Request:": 30, + "Comments:": 10, + // Add more keys and limits if needed + }; + int limit = limits[title] ?? 50; // Default limit if title not found + bool exceedsLimit = value.length > limit; + + String wrapText(String text, int maxLineLength) { + final pattern = RegExp('.{1,$maxLineLength}(\\s+|\$)'); + return pattern.allMatches(text).map((m) => m.group(0)!).join('\n'); + } + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 100, + child: Text( + title, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ), + SizedBox(width: 8), + Expanded( + child: + exceedsLimit + ? Tooltip( + message: wrapText(value, 50), + decoration: BoxDecoration( + color: Colors.grey.shade200, // Black background + borderRadius: BorderRadius.circular(6), + ), + textStyle: TextStyle( + color: Colors.black, + ), // Tooltip text color + padding: EdgeInsets.all(8), + preferBelow: false, + child: Text( + value.substring(0, limit) + "...", + style: GoogleFonts.poppins(fontSize: 12), + overflow: TextOverflow.ellipsis, + ), + ) + : Text(value, style: GoogleFonts.poppins(fontSize: 12)), + ), + ], + ); + } } diff --git a/lib/Screens/plans/dynamic_itinerary_stepper.dart b/lib/Screens/plans/dynamic_itinerary_stepper.dart index 13c5159..949aa08 100644 --- a/lib/Screens/plans/dynamic_itinerary_stepper.dart +++ b/lib/Screens/plans/dynamic_itinerary_stepper.dart @@ -856,7 +856,7 @@ class DynamicItineraryState extends State { margin: EdgeInsets.only( top: 40, ), // Push it down to make room for the tab bar - padding: EdgeInsets.all(12), + padding: EdgeInsets.only(top: 12, bottom: 12, left: 3, right: 3), decoration: BoxDecoration( color: Colors.white, // Card background // color: Colors.yellow.shade50, // Card background diff --git a/lib/Screens/userManagement/create_user/create_user.dart b/lib/Screens/userManagement/create_user/create_user.dart index 9d811d5..b3033fc 100644 --- a/lib/Screens/userManagement/create_user/create_user.dart +++ b/lib/Screens/userManagement/create_user/create_user.dart @@ -181,7 +181,8 @@ class _CreateUserFormDetialsState extends State { "first_approver": selectedFirstApprover, "second_approver": selectedSecondApprover, "third_approver": selectedThirdApprover, - "exceptional_approver": selectedExceptionalApprover, + "fourth_approver": selectedExceptionalApprover, + // "exceptional_approver": selectedExceptionalApprover, "delegated_to_user_id": selectedSubstituteApprover, // "passport_number": controllers["passportNumber"]?.text, // "place_of_issue": controllers["placeOfIssue"]?.text, @@ -300,9 +301,14 @@ class _CreateUserFormDetialsState extends State { apiselectedUser?["third_approver"]?.toString() ?? ""; } - if (apiselectedUser?["exceptional_approver"] != null) { + // if (apiselectedUser?["exceptional_approver"] != null) { + // selectedExceptionalApprover = + // apiselectedUser?["exceptional_approver"]?.toString() ?? ""; + // } + + if (apiselectedUser?["fourth_approver"] != null) { selectedExceptionalApprover = - apiselectedUser?["exceptional_approver"]?.toString() ?? ""; + apiselectedUser?["fourth_approver"]?.toString() ?? ""; } if (apiselectedUser?["delegated_to_user_id"] != null) { @@ -1329,9 +1335,11 @@ class _CreateUserFormDetialsState extends State { print("📨 Response: ${response.body}"); - if(roleId == "4"){ context.go('/listPlan'); } - else{ context.go('/listUser'); } - + if (roleId == "4") { + context.go('/listPlan'); + } else { + context.go('/listUser'); + } } else { print("❌ Submission failed. Status: ${response.statusCode}"); print("📨 Body: ${response.body}"); diff --git a/lib/Screens/userManagement/create_user/office_details.dart b/lib/Screens/userManagement/create_user/office_details.dart index b9c53b4..95eae48 100644 --- a/lib/Screens/userManagement/create_user/office_details.dart +++ b/lib/Screens/userManagement/create_user/office_details.dart @@ -191,18 +191,34 @@ class OfficeDetailsState extends State { fetchUsers(); fetchFindGroup(); - - _addFocusListener(_employeeCodeFocusNode, (focus) => _employeeCodeFocus = focus); - _addFocusListener(_departmentFocusNode, (focus) => _departmentFocus = focus); - _addFocusListener(_groupFocusNode, (focus) => _groupFocus = focus); - _addFocusListener(_firstApprovalFocusNode, (focus) => _firstApprovalFocus = focus); - _addFocusListener(_secondApprovalFocusNode, (focus) => _secondApprovalFocus = focus); - _addFocusListener(_thirdApprovalFocusNode, (focus) => _thirdApprovalFocus = focus); - _addFocusListener(_exceptionalApprovalFocusNode, (focus) => _exceptionalApprovalFocus = focus); - _addFocusListener(_delegateFocusNode, (focus) => _delegateFocus = focus); - _addFocusListener(_startDateFocusNode, (focus) => _startDateFocus = focus); - _addFocusListener(_endDateFocusNode, (focus) => _endDateFocus = focus); - + _addFocusListener( + _employeeCodeFocusNode, + (focus) => _employeeCodeFocus = focus, + ); + _addFocusListener( + _departmentFocusNode, + (focus) => _departmentFocus = focus, + ); + _addFocusListener(_groupFocusNode, (focus) => _groupFocus = focus); + _addFocusListener( + _firstApprovalFocusNode, + (focus) => _firstApprovalFocus = focus, + ); + _addFocusListener( + _secondApprovalFocusNode, + (focus) => _secondApprovalFocus = focus, + ); + _addFocusListener( + _thirdApprovalFocusNode, + (focus) => _thirdApprovalFocus = focus, + ); + _addFocusListener( + _exceptionalApprovalFocusNode, + (focus) => _exceptionalApprovalFocus = focus, + ); + _addFocusListener(_delegateFocusNode, (focus) => _delegateFocus = focus); + _addFocusListener(_startDateFocusNode, (focus) => _startDateFocus = focus); + _addFocusListener(_endDateFocusNode, (focus) => _endDateFocus = focus); } void _addFocusListener(FocusNode node, Function(bool) updateState) { @@ -219,14 +235,14 @@ class OfficeDetailsState extends State { setState(() { layoutColor = - layoutString != null - ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; bodyColor = - bodyStringColor != null - ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); } @@ -462,21 +478,18 @@ class OfficeDetailsState extends State { return Container( color: Colors.white, child: - widget.isDesktop - ? Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - buildExceptionApprover(isDesktop), - Spacer(), - ], - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - buildExceptionApprover(isDesktop), - SizedBox(height: 8), // Vertical space - ], - ), + widget.isDesktop + ? Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [buildExceptionApprover(isDesktop), Spacer()], + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildExceptionApprover(isDesktop), + SizedBox(height: 8), // Vertical space + ], + ), ); } @@ -669,95 +682,100 @@ class OfficeDetailsState extends State { // Request focus when user taps _departmentFocusNode?.requestFocus(); }, - child: DropdownSearch( - selectedItem: departmentMap[selectedDepartment], - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - menuProps: const MenuProps(backgroundColor: Colors.white), - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins(fontSize: 11.5), + child: DropdownSearch( + selectedItem: departmentMap[selectedDepartment], + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + menuProps: const MenuProps(backgroundColor: Colors.white), + itemBuilder: + (context, item, isSelected) => Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 11.5), + ), + ), + constraints: BoxConstraints(maxHeight: 200), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Department...", + contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), - constraints: BoxConstraints(maxHeight: 200), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Department...", - contentPadding: EdgeInsets.symmetric(horizontal: 10), ), + items: departmentMap.values.toList(), + + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (_departmentFocus) ? (layoutColor) : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_departmentFocus) ? (layoutColor) : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: (layoutColor ?? Colors.grey), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + // contentPadding: EdgeInsets.symmetric(horizontal: 1), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select Department", + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), + ), + onChanged: + widget.isViewMode + ? null + : (String? newValue) { + if (newValue == null) return; + + final departmentId = + departmentMap.entries + .firstWhere( + (entry) => entry.value == newValue, + ) + .key; + + setState(() { + selectedDepartment = departmentId; + }); + + widget.onDepartmentChanged?.call( + departmentId, + ); // Send department_id + }, ), ), - items: departmentMap.values.toList(), - - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_departmentFocus) - ? (layoutColor) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_departmentFocus) - ? (layoutColor) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - // contentPadding: EdgeInsets.symmetric(horizontal: 1), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select Department", - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ), - ), - onChanged: - widget.isViewMode - ? null - : (String? newValue) { - if (newValue == null) return; - - final departmentId = - departmentMap.entries - .firstWhere((entry) => entry.value == newValue) - .key; - - setState(() { - selectedDepartment = departmentId; - }); - - widget.onDepartmentChanged?.call( - departmentId, - ); // Send department_id - }, - ),),), + ), ), ), ], @@ -840,113 +858,121 @@ class OfficeDetailsState extends State { // Request focus when user taps _groupFocusNode?.requestFocus(); }, - child: - apiAllGroups == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - selectedItem: groupMap[selectedLevel], - enabled: !widget.isViewMode, + child: + apiAllGroups == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + selectedItem: groupMap[selectedLevel], + enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - menuProps: const MenuProps( - backgroundColor: Colors.white, - ), - showSearchBox: true, - fit: FlexFit.loose, // Allows flexible height - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins(fontSize: 11.5), + popupProps: PopupProps.menu( + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + showSearchBox: true, + fit: FlexFit.loose, // Allows flexible height + itemBuilder: + (context, item, isSelected) => Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 11.5), + ), + ), + constraints: BoxConstraints(maxHeight: 250), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Group...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + ), ), ), - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Group...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, + ), + + // items: apiAllGroups!.map((group) { + // return "${group['name']} "; + // }).toList(), + items: + apiAllGroups!.map((group) { + return group['name'] + .toString() + .trim(); // <-- trim spaces + }).toList(), + + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (_groupFocus ?? false) + ? (layoutColor ?? Colors.white) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_groupFocus ?? false) + ? (layoutColor ?? Colors.white) + : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: (layoutColor ?? Colors.grey), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), ), ), + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: GoogleFonts.poppins(fontSize: 12), + ), + ), + + onChanged: (String? newValue) { + if (newValue == null) return; + + final levelId = + groupMap.entries + .firstWhere( + (entry) => entry.value == newValue, + ) + .key; + + setState(() { + selectedLevel = levelId; + }); + + widget.onLevelChanged?.call( + levelId, + ); // ✅ pass the ID not the name + }, ), - ), - - // items: apiAllGroups!.map((group) { - // return "${group['name']} "; - // }).toList(), - items: - apiAllGroups!.map((group) { - return group['name'] - .toString() - .trim(); // <-- trim spaces - }).toList(), - - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_groupFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_groupFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: GoogleFonts.poppins(fontSize: 12), - ), - ), - - onChanged: (String? newValue) { - if (newValue == null) return; - - final levelId = - groupMap.entries - .firstWhere((entry) => entry.value == newValue) - .key; - - setState(() { - selectedLevel = levelId; - }); - - widget.onLevelChanged?.call( - levelId, - ); // ✅ pass the ID not the name - }, - ), - ),), + ), + ), ), ), ], @@ -986,7 +1012,7 @@ class OfficeDetailsState extends State { focusNode: _firstApprovalFocusNode, onFocusChange: (hasFocus) { setState(() { - _firstApprovalFocus= hasFocus; + _firstApprovalFocus = hasFocus; }); }, child: GestureDetector( @@ -994,124 +1020,148 @@ class OfficeDetailsState extends State { // Request focus when user taps _firstApprovalFocusNode?.requestFocus(); }, - child: - apiUserData == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - selectedItem: userMap[selectedFirstApprover], - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, // Allows flexible height - menuProps: const MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins( - fontSize: 11.5, + child: + apiUserData == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + selectedItem: + userMap[selectedFirstApprover], + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: + FlexFit + .loose, // Allows flexible height + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => + Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins( + fontSize: 11.5, + ), + ), + ), + constraints: BoxConstraints( + maxHeight: 250, + ), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search User...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, ), ), ), - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search User...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - ), ), - ), - ), - items: - apiUserData!.map((user) { - return "${user['first_name']} ${user['last_name']}"; - }).toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_firstApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_firstApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: GoogleFonts.poppins( - fontSize: 12, + items: + apiUserData!.map((user) { + return "${user['first_name']} ${user['last_name']}"; + }).toList(), + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: + InputDecoration( + border: OutlineInputBorder( + borderRadius: + BorderRadius.circular(8), + borderSide: BorderSide( + color: + (_firstApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_firstApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: + OutlineInputBorder( + borderSide: BorderSide( + color: + (layoutColor ?? + Colors.grey), + width: 0.5, + ), + ), + contentPadding: + EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: GoogleFonts.poppins( + fontSize: 12, + ), + ), ), - ), - ), - // onChanged: (String? newValue) { - // setState(() { - // selectedFirstApprover = userMap.entries - // .firstWhere( - // (entry) => entry.value == newValue) - // .key; - // - // // if (selectedCountry!.isNotEmpty) { - // // errorMessages.remove("country_code"); - // // } - // }); - // widget.onFirstApproverChanged?.call(newValue); - // }, - onChanged: (String? newValue) { - if (newValue == null) return; + // onChanged: (String? newValue) { + // setState(() { + // selectedFirstApprover = userMap.entries + // .firstWhere( + // (entry) => entry.value == newValue) + // .key; + // + // // if (selectedCountry!.isNotEmpty) { + // // errorMessages.remove("country_code"); + // // } + // }); + // widget.onFirstApproverChanged?.call(newValue); + // }, + onChanged: (String? newValue) { + if (newValue == null) return; - final approverId = - userMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; + final approverId = + userMap.entries + .firstWhere( + (entry) => + entry.value == newValue, + ) + .key; - setState(() { - selectedFirstApprover = approverId; - }); + setState(() { + selectedFirstApprover = approverId; + }); - widget.onFirstApproverChanged?.call( - approverId, - ); // ✅ not newValue, but approverId - }, - ), - ),), + widget.onFirstApproverChanged?.call( + approverId, + ); // ✅ not newValue, but approverId + }, + ), + ), + ), ), ), ], @@ -1166,123 +1216,147 @@ class OfficeDetailsState extends State { // Request focus when user taps _secondApprovalFocusNode?.requestFocus(); }, - child: - apiUserData == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - selectedItem: userMap[selectedSecondApprover], - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, // Allows flexible height - menuProps: const MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins( - fontSize: 11.5, + child: + apiUserData == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + selectedItem: + userMap[selectedSecondApprover], + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: + FlexFit + .loose, // Allows flexible height + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => + Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins( + fontSize: 11.5, + ), + ), + ), + constraints: BoxConstraints( + maxHeight: 250, + ), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search User...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, ), ), ), - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search User...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - ), ), - ), - ), - items: - apiUserData!.map((user) { - return "${user['first_name']} ${user['last_name']}"; - }).toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_secondApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_secondApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: GoogleFonts.poppins( - fontSize: 12, + items: + apiUserData!.map((user) { + return "${user['first_name']} ${user['last_name']}"; + }).toList(), + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: + InputDecoration( + border: OutlineInputBorder( + borderRadius: + BorderRadius.circular(8), + borderSide: BorderSide( + color: + (_secondApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_secondApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: + OutlineInputBorder( + borderSide: BorderSide( + color: + (layoutColor ?? + Colors.grey), + width: 0.5, + ), + ), + contentPadding: + EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: GoogleFonts.poppins( + fontSize: 12, + ), + ), ), - ), - ), - onChanged: (String? newValue) { - if (newValue == null) return; + onChanged: (String? newValue) { + if (newValue == null) return; - final approverId = - userMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; + final approverId = + userMap.entries + .firstWhere( + (entry) => + entry.value == newValue, + ) + .key; - setState(() { - selectedSecondApprover = approverId; - }); + setState(() { + selectedSecondApprover = approverId; + }); - widget.onSecondApproverChanged?.call( - approverId, - ); // ✅ not newValue, but approverId - }, - // onChanged: (String? newValue) { - // setState(() { - // selectedSecondApprover = userMap.entries - // .firstWhere( - // (entry) => entry.value == newValue) - // .key; - // - // // if (selectedCountry!.isNotEmpty) { - // // errorMessages.remove("country_code"); - // // } - // }); - // }, - ), - ),), + widget.onSecondApproverChanged?.call( + approverId, + ); // ✅ not newValue, but approverId + }, + // onChanged: (String? newValue) { + // setState(() { + // selectedSecondApprover = userMap.entries + // .firstWhere( + // (entry) => entry.value == newValue) + // .key; + // + // // if (selectedCountry!.isNotEmpty) { + // // errorMessages.remove("country_code"); + // // } + // }); + // }, + ), + ), + ), ), ), ], @@ -1337,122 +1411,146 @@ class OfficeDetailsState extends State { // Request focus when user taps _thirdApprovalFocusNode?.requestFocus(); }, - child: - apiUserData == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - selectedItem: userMap[selectedThirdApprover], - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, // Allows flexible height - menuProps: const MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins( - fontSize: 11.5, + child: + apiUserData == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + selectedItem: + userMap[selectedThirdApprover], + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: + FlexFit + .loose, // Allows flexible height + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => + Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins( + fontSize: 11.5, + ), + ), + ), + constraints: BoxConstraints( + maxHeight: 250, + ), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search User...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, ), ), ), - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search User...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - ), ), - ), - ), - items: - apiUserData!.map((user) { - return "${user['first_name']} ${user['last_name']}"; - }).toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_thirdApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_thirdApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: GoogleFonts.poppins( - fontSize: 12, + items: + apiUserData!.map((user) { + return "${user['first_name']} ${user['last_name']}"; + }).toList(), + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: + InputDecoration( + border: OutlineInputBorder( + borderRadius: + BorderRadius.circular(8), + borderSide: BorderSide( + color: + (_thirdApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_thirdApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: + OutlineInputBorder( + borderSide: BorderSide( + color: + (layoutColor ?? + Colors.grey), + width: 0.5, + ), + ), + contentPadding: + EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + ), ), - ), - ), - onChanged: (String? newValue) { - if (newValue == null) return; + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: GoogleFonts.poppins( + fontSize: 12, + ), + ), + ), + onChanged: (String? newValue) { + if (newValue == null) return; - final approverId = - userMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; + final approverId = + userMap.entries + .firstWhere( + (entry) => + entry.value == newValue, + ) + .key; - setState(() { - selectedThirdApprover = approverId; - }); + setState(() { + selectedThirdApprover = approverId; + }); - widget.onThirdApproverChanged?.call( - approverId, - ); // ✅ not newValue, but approverId - }, - // onChanged: (String? newValue) { - // setState(() { - // selectedThirdApprover = userMap.entries - // .firstWhere( - // (entry) => entry.value == newValue) - // .key; - // - // // if (selectedCountry!.isNotEmpty) { - // // errorMessages.remove("country_code"); - // // } - // }); - // }, - ), - ),), + widget.onThirdApproverChanged?.call( + approverId, + ); // ✅ not newValue, but approverId + }, + // onChanged: (String? newValue) { + // setState(() { + // selectedThirdApprover = userMap.entries + // .firstWhere( + // (entry) => entry.value == newValue) + // .key; + // + // // if (selectedCountry!.isNotEmpty) { + // // errorMessages.remove("country_code"); + // // } + // }); + // }, + ), + ), + ), ), ), ], @@ -1480,7 +1578,7 @@ class OfficeDetailsState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Exceptional Approver", + "Fourth Approver", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, @@ -1507,111 +1605,132 @@ class OfficeDetailsState extends State { // Request focus when user taps _exceptionalApprovalFocusNode?.requestFocus(); }, - child: - apiUserData == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - selectedItem: userMap[selectedExceptionalApprover], - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, // Allows flexible height - menuProps: const MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins( - fontSize: 11.5, - ), - ), - ), - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search User...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - ), - ), - ), - ), - items: - apiUserData!.map((user) { - return "${user['first_name']} ${user['last_name']}"; - }).toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_exceptionalApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_exceptionalApprovalFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.white), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: GoogleFonts.poppins( - fontSize: 12, - ), - ), - ), + child: + apiUserData == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + selectedItem: + userMap[selectedExceptionalApprover], + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: + FlexFit + .loose, // Allows flexible height + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => + Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins( + fontSize: 11.5, + ), + ), + ), + constraints: BoxConstraints( + maxHeight: 250, + ), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search User...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + ), + ), + ), + ), + items: + apiUserData!.map((user) { + return "${user['first_name']} ${user['last_name']}"; + }).toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular( + 8, + ), + borderSide: BorderSide( + color: + (_exceptionalApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_exceptionalApprovalFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (layoutColor ?? Colors.white), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: GoogleFonts.poppins( + fontSize: 12, + ), + ), + ), - onChanged: (String? newValue) { - if (newValue == null) return; + onChanged: (String? newValue) { + if (newValue == null) return; - final approverId = - userMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; + final approverId = + userMap.entries + .firstWhere( + (entry) => + entry.value == newValue, + ) + .key; - setState(() { - selectedExceptionalApprover = approverId; - }); + setState(() { + selectedExceptionalApprover = + approverId; + }); - widget.onExceptionalApproverChanged?.call( - approverId, - ); // ✅ not newValue, but approverId - }, + widget.onExceptionalApproverChanged?.call( + approverId, + ); // ✅ not newValue, but approverId + }, + ), + ), ), - ),), ), ), ], @@ -1625,7 +1744,6 @@ class OfficeDetailsState extends State { ); } - Widget buildApproverSubstitute1(bool isDesktop) { return Container( color: Colors.white, @@ -1666,128 +1784,151 @@ class OfficeDetailsState extends State { onTap: () { _delegateFocusNode?.requestFocus(); }, - child: - apiUserData == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - // selectedItem: userMap[selectedSubstituteApprover], - selectedItem: - selectedSubstituteApprover != null - ? userMap[selectedSubstituteApprover] - : null, - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, // Allows flexible height - menuProps: const MenuProps( - backgroundColor: Colors.white, - ), - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins( - fontSize: 11.5, + child: + apiUserData == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + // selectedItem: userMap[selectedSubstituteApprover], + selectedItem: + selectedSubstituteApprover != null + ? userMap[selectedSubstituteApprover] + : null, + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: + FlexFit + .loose, // Allows flexible height + menuProps: const MenuProps( + backgroundColor: Colors.white, + ), + itemBuilder: + (context, item, isSelected) => + Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins( + fontSize: 11.5, + ), + ), + ), + constraints: BoxConstraints( + maxHeight: 133, + ), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search User...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, ), ), ), - constraints: BoxConstraints(maxHeight: 133), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search User...", - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - ), ), - ), - ), - items: - apiUserData!.map((user) { - return "${user['first_name']} ${user['last_name']}"; - }).toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_delegateFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_delegateFocus ?? false) - ? (layoutColor ?? Colors.white) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: GoogleFonts.poppins( - fontSize: 12, + items: + apiUserData!.map((user) { + return "${user['first_name']} ${user['last_name']}"; + }).toList(), + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: + InputDecoration( + border: OutlineInputBorder( + borderRadius: + BorderRadius.circular(8), + borderSide: BorderSide( + color: + (_delegateFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_delegateFocus ?? + false) + ? (layoutColor ?? + Colors.white) + : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: + OutlineInputBorder( + borderSide: BorderSide( + color: + (layoutColor ?? + Colors.grey), + width: 0.5, + ), + ), + contentPadding: + EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: GoogleFonts.poppins( + fontSize: 12, + ), + ), ), - ), - ), - // onChanged: (String? newValue) { - // setState(() { - // selectedFirstApprover = userMap.entries - // .firstWhere( - // (entry) => entry.value == newValue) - // .key; - // - // // if (selectedCountry!.isNotEmpty) { - // // errorMessages.remove("country_code"); - // // } - // }); - // widget.onFirstApproverChanged?.call(newValue); - // }, - onChanged: (String? newValue) { - if (newValue == null) return; + // onChanged: (String? newValue) { + // setState(() { + // selectedFirstApprover = userMap.entries + // .firstWhere( + // (entry) => entry.value == newValue) + // .key; + // + // // if (selectedCountry!.isNotEmpty) { + // // errorMessages.remove("country_code"); + // // } + // }); + // widget.onFirstApproverChanged?.call(newValue); + // }, + onChanged: (String? newValue) { + if (newValue == null) return; - final approverId = - userMap.entries - .firstWhere( - (entry) => entry.value == newValue, - ) - .key; + final approverId = + userMap.entries + .firstWhere( + (entry) => + entry.value == newValue, + ) + .key; - setState(() { - selectedSubstituteApprover = approverId; - }); + setState(() { + selectedSubstituteApprover = approverId; + }); - widget.onFirstSubsApproverChanged?.call( - approverId, - ); // ✅ not newValue, but approverId - }, - ), - ),), + widget.onFirstSubsApproverChanged?.call( + approverId, + ); // ✅ not newValue, but approverId + }, + ), + ), + ), ), ), ], @@ -1869,7 +2010,7 @@ class OfficeDetailsState extends State { isDesktop: widget.isDesktop, child: SizedBox( height: 40, - child:Focus( + child: Focus( focusNode: _startDateFocusNode, onKeyEvent: (FocusNode node, KeyEvent event) { // Only act on KeyDown and when Enter is pressed @@ -1886,13 +2027,16 @@ class OfficeDetailsState extends State { behavior: HitTestBehavior.opaque, onTapDown: (details) { _startDateFocusNode?.requestFocus(); - _selectCheckOutDate(context); + _selectCheckOutDate(context); }, child: AbsorbPointer( child: TextField( controller: widget.controllers["delegationStartDate"], readOnly: true, - style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), decoration: InputDecoration( labelText: "Select Date", labelStyle: GoogleFonts.poppins( @@ -2020,7 +2164,7 @@ class OfficeDetailsState extends State { isDesktop: widget.isDesktop, child: SizedBox( height: 40, - child:Focus( + child: Focus( focusNode: _endDateFocusNode, onKeyEvent: (FocusNode node, KeyEvent event) { // Only act on KeyDown and when Enter is pressed @@ -2041,7 +2185,7 @@ class OfficeDetailsState extends State { onTapDown: (details) { if (!widget.isViewMode) { _selectForexEndDate(context).then((_) { - _endDateFocusNode?.requestFocus(); + _endDateFocusNode?.requestFocus(); }); } }, @@ -2049,7 +2193,10 @@ class OfficeDetailsState extends State { child: TextField( controller: widget.controllers["delegationEndDate"], readOnly: true, - style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), decoration: InputDecoration( labelText: "Select Date", labelStyle: GoogleFonts.poppins( diff --git a/lib/config/apiUrl.dart b/lib/config/apiUrl.dart index 3f0712c..3c5438f 100644 --- a/lib/config/apiUrl.dart +++ b/lib/config/apiUrl.dart @@ -1,7 +1,7 @@ //api url // const String apiUrl = 'http://localhost/tstat_be'; -const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; -// const String apiUrl = 'https://apitest.tripapprovaltool.com/tstat_be'; +// const String apiUrl = 'https://uat.tripapprovaltool.com/tstat_be'; +const String apiUrl = 'https://apitest.tripapprovaltool.com/tstat_be'; /** Note : Adfactor UAT BE URL * File : web/index.html - change below