import 'dart:convert'; import 'dart:core'; import 'dart:typed_data'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:frontend/config/apiUrl.dart'; import 'package:intl/intl.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:universal_html/html.dart' as html; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../utils/pagination.dart'; import '../../widgets/custom_breadcrumb_navigation.dart'; import '../../widgets/custom_text_field.dart'; class MISforex extends StatefulWidget { const MISforex({super.key}); @override _MISforexState createState() => _MISforexState(); } class _MISforexState extends State with SingleTickerProviderStateMixin { final ApiService apiService = ApiService(); String? userId; String? orgId; String? roleUser; String? token; Color? layoutColor; Color? bodyColor; int currentPage = 0; int itemsPerPage = 10; String selectedTabName = 'international'; Map focusNodes = {}; Map focusStates = {}; Map textControllers = {}; Map errorMessages = {}; // Map MISforexReport = {}; List> internationalData = []; // Map internationalData = {}; List> filteredInternational = []; TextEditingController searchInternationalController = TextEditingController(); bool loaderFlag = false; @override void initState() { super.initState(); loadInitialData(); _checkAuthAndLoadData(); if (!textControllers.containsKey("from_date")) { textControllers["from_date"] = TextEditingController(); } if (!textControllers.containsKey("to_date")) { textControllers["to_date"] = TextEditingController(); } if (!focusNodes.containsKey("from_date")) { focusNodes["from_date"] = FocusNode(); } if (!focusNodes.containsKey("to_date")) { focusNodes["to_date"] = FocusNode(); } if (!focusStates.containsKey("to_date")) { focusStates["to_date"] = false; } if (!focusStates.containsKey("from_date")) { focusStates["from_date"] = false; } // Add focus listeners focusNodes.forEach((key, focusNode) { _addFocusListener(focusNode, (focus) { setState(() { focusStates[key] = focus; }); }); }); getToken(); // fetchMISforexReport(); } void _addFocusListener(FocusNode node, Function(bool) updateState) { node.addListener(() { setState(() { updateState(node.hasFocus); }); }); } void loadInitialData() async { String? layoutString = await getLayoutColor(); String? bodyStringColor = await getBodyColor(); setState(() { layoutColor = layoutString != null ? Color(int.parse(layoutString)) : Colors.redAccent; bodyColor = bodyStringColor != null ? Color(int.parse(bodyStringColor)) : Colors.white; }); } void _checkAuthAndLoadData() async { final String? token = await getToken(); // Your async function to get token if (token == null || token.isEmpty) { // Token doesn't exist → redirect to login context.go( "/", ); // or use: router.go("/") if you're using `GoRouter` directly return; } if (!mounted) return; try { WidgetsBinding.instance.addPostFrameCallback((_) { loadInitialData(); }); } catch (e) { print("Forex report : $e"); } } Future initializeData() async { token = await getToken(); userId = await getUserId(); orgId = await getOrgId(); roleUser = await getRoleUser(); if (token == null || userId == null) { print("Token or USerId missing"); return; } } Future getUserId() async { final prefs = await SharedPreferences.getInstance(); final String? userDataString = prefs.getString('user_data'); if (userDataString != null) { try { final Map userData = jsonDecode(userDataString); return userData["user_id"]?.toString(); } catch (e) { return null; } } return null; } Future getOrgId() async { final prefs = await SharedPreferences.getInstance(); final String? userDataString = prefs.getString('user_data'); if (userDataString != null) { try { final Map userData = jsonDecode(userDataString); return userData["org_id"]?.toString(); } catch (e) { return null; } } return null; } Future getToken() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString('auth_token'); } Future handleSubmit() async { errorMessages.remove("from_date"); errorMessages.remove("to_date"); setState(() { internationalData = []; currentPage = 0; itemsPerPage = 10; }); final fromDateText = textControllers["from_date"]?.text; final toDateText = textControllers["to_date"]?.text; if (fromDateText == null || fromDateText.isEmpty || toDateText == null || toDateText.isEmpty) { fromDateText == null || fromDateText.isEmpty ? errorMessages["from_date"] = "Required" : errorMessages.remove("from_date"); toDateText == null || toDateText.isEmpty ? errorMessages["to_date"] = "Required" : errorMessages.remove("to_date"); setState(() {}); return; } // Parse the string to DateTime using the correct format final dateFormat = DateFormat('dd-MM-yyyy'); final DateTime fromDate = dateFormat.parse(fromDateText); final DateTime toDate = dateFormat.parse(toDateText); // Check if from date is after to date if (fromDate.isAfter(toDate)) { errorMessages["to_date"] = "Invalid Date Range"; setState(() {}); return; } setState(() { loaderFlag = true; }); // Format for API request final formattedfromDate = DateFormat('yyyy-MM-dd').format(fromDate); final formattedtoDate = DateFormat('yyyy-MM-dd').format(toDate); // Fetch and update loaderFlag = true; try { final result = await apiService.CallReports( 'misForexReport', jsonEncode({ "fromDate": '$formattedfromDate', "toDate": '$formattedtoDate', }), ); setState(() { // domesticData = List>.from(result['data']['domestic'] ?? []); internationalData = List>.from( result['status'] == 'success' ? result['data'] ?? [] : [], ); filteredInternational = internationalData; loaderFlag = false; }); } catch (e) { // handle error setState(() { loaderFlag = false; // domesticData = []; internationalData = []; }); } } Future handleDownload() async { final dateFormat = DateFormat('dd-MM-yyyy'); if (textControllers["from_date"]!.text.isEmpty || textControllers["to_date"]!.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: Colors.redAccent, content: Text("Please choose a valid date range."), behavior: SnackBarBehavior.floating, ), ); return; } final DateTime fromDate = dateFormat.parse( textControllers["from_date"]!.text, ); final DateTime toDate = dateFormat.parse(textControllers["to_date"]!.text); final formattedFromDate = DateFormat('yyyy-MM-dd').format(fromDate); final formattedToDate = DateFormat('yyyy-MM-dd').format(toDate); final name = 'MIS Forex - International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})'; final safeName = name.replaceAll(RegExp(r'[^\w\s-]'), ''); final excelName = '$safeName'; final result = await apiService.reportExcelDownload( 'misForexReport', jsonEncode({ "fromDate": formattedFromDate, "toDate": formattedToDate, "export": selectedTabName, }), excelName, ); ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: result['status'] ? Colors.green : Colors.red, content: Text(result['message']), behavior: SnackBarBehavior.floating, ), ); } void handleInternationalFilter(String query) { final lowerQuery = query.toLowerCase(); setState(() { filteredInternational = internationalData.where((object) { final fromDateRaw = object['forex_from_date']; String newFromDate = ''; if (fromDateRaw != null && fromDateRaw is String) { try { final parsedDate = DateTime.parse(fromDateRaw); newFromDate = '${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}'; } catch (e) { // fallback if date is not parsable newFromDate = fromDateRaw; } } final toDateRaw = object['flight_travel_date']; String newToDate = ''; if (toDateRaw != null && toDateRaw is String) { try { final parsedDate = DateTime.parse(toDateRaw); newToDate = '${parsedDate.day.toString().padLeft(2, '0')}-${parsedDate.month.toString().padLeft(2, '0')}-${parsedDate.year}'; } catch (e) { // fallback if date is not parsable newToDate = toDateRaw; } } return (object['plan_id']?.toLowerCase().contains(lowerQuery) ?? false) || (object['employee_code']?.toLowerCase().contains(lowerQuery) ?? false) || (object['passenger_name']?.toLowerCase().contains(lowerQuery) ?? false) || (object['so_number']?.toLowerCase().contains(lowerQuery) ?? false) || (object['functional_department']?.toLowerCase().contains(lowerQuery) ?? false) || (object['visiting_country']?.toLowerCase().contains(lowerQuery) ?? false) || (object['amount']?.toLowerCase().contains(lowerQuery) ?? false) || (newFromDate.toLowerCase().contains(lowerQuery)) || (newToDate.toLowerCase().contains(lowerQuery)); }).toList(); currentPage = 0; }); print("handleInternationalFilter > Total entries: ${filteredInternational?.length ?? 0}"); } @override // Widget build(BuildContext context) { // // TODO: implement build // throw UnimplementedError(); // } Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), appBar: CustomAppBar(isDesktop: isDesktop), drawer: CustomDrawer(isDesktop: false), body: Padding( padding: isDesktop ? EdgeInsets.symmetric( horizontal: MediaQuery.of(context).size.width * 0.1, // 30% of screen width as horizontal padding vertical: MediaQuery.of(context).size.height * 0, // 5% of screen height as vertical padding ) : EdgeInsets.all(0), child: Row( children: [ // if (isDesktop) CustomDrawer(isDesktop: true), // const Expanded(child: Center(child: Text("User Page Content"))), Expanded(child: buildMISforexLayout(isDesktop)), ], ), ), ); }, ); } Widget buildMISforexLayout(bool isDesktop) { return Container(child: buildMISforexFormLayout(isDesktop)); } Widget buildMISforexFormLayout(bool isDesktop) { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, padding: const EdgeInsets.only(top: 5, bottom: 5, left: 20, right: 20), // color: Colors.brown, height: isDesktop ? MediaQuery.of(context).size.height * 1 : MediaQuery.of(context).size.height, decoration: BoxDecoration( border: isDesktop ? Border.all(width: 2, color: Colors.white) : null, color: isDesktop ? Colors.white : Color(0xFFFCFCFC), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // ------------------- First Row ------------------- // ------------------- First Row ------------------- Container( color: Colors.white, child: isDesktop ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ buildTitle(isDesktop), Spacer(), buildExports(isDesktop) ], ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ buildTitle(isDesktop), SizedBox(height: 8), buildExports(isDesktop) ], ) ), SizedBox(height: 5), // ------------------- Second Row ------------------- Container( color: Colors.white, child: isDesktop ? Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ buildFromDateField(isDesktop), Spacer(), buildToDateField(isDesktop), Spacer(), // Space after Last Name buildSearchButton(isDesktop), ], ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ buildFromDateField(isDesktop), SizedBox(height: 8), // Vertical space buildToDateField(isDesktop), SizedBox(height: 8), buildSearchButton(isDesktop), ], ), ), SizedBox(height: 5), // ------------------- Third Row ------------------- Column( children: [ Container( height: MediaQuery.of(context).size.height * 0.6, child: internationalData.isEmpty ? Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: MediaQuery.of(context).size.height / 4), Text( "No Records Found", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, color: Colors.black54, ), ), const SizedBox(height: 10), Text( "Please ensure the selected dates contain report data.", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.black54, ), ), ], ), ), ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Padding( padding: const EdgeInsets.symmetric( horizontal: 16.0, vertical: 8, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ /// Title on the left Expanded( child: Text( "International Report (From: ${textControllers["from_date"]?.text} To: ${textControllers["to_date"]?.text})", style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey[700], ), overflow: TextOverflow.ellipsis, // Ensures title doesn't overflow ), ), SizedBox(width: 16), Container( width: MediaQuery.of(context).size.width * 0.2, height: 40, child: TextField( controller: searchInternationalController, onChanged: handleInternationalFilter, decoration: InputDecoration( hintText: "Search ...", hintStyle: TextStyle( fontSize: 12, color: Color(0xFF9E9DBD), ), prefixIcon: Icon( Icons.search, color: Color(0xFF9E9DBD), size: 18, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Colors.grey.shade200, width: 0.5, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: Colors.grey.shade300, width: 1, ), ), ), style: GoogleFonts.poppins(fontSize: 12), ), ), ]) ), // Table container Container( height: isDesktop ? MediaQuery.of(context).size.height * 0.51 : 200, child: LayoutBuilder( builder: (context, constraints) { final double minWidth = isDesktop ? constraints.maxWidth : 1300; List> newInternationalData =filteredInternational.isNotEmpty ? filteredInternational : internationalData; // Pagination logic List> paginatedInternational = newInternationalData .skip(currentPage * itemsPerPage) .take(itemsPerPage) .toList(); return ((searchInternationalController.text.isNotEmpty && filteredInternational.isEmpty) ? Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: MediaQuery.of(context).size.height / 4), Text( "No Records Found", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, color: Colors.black54, ), ), const SizedBox(height: 10), Text( "Please ensure the selected dates contain report data.", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.black54, ), ), ], ), ), ) :Column( children: [ Expanded( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: ConstrainedBox( constraints: BoxConstraints( minWidth: minWidth, ), child: SingleChildScrollView( scrollDirection: Axis.vertical, child: DataTable( dividerThickness: 0.5, columnSpacing: isDesktop ? 30.0 : 24.0, border: TableBorder( horizontalInside: BorderSide( width: 0.5, color: Colors.grey.shade200, ), ), columns: [ DataColumn( label: Text( 'Plan Id', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Employee Code', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Passenger Name', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'SO Number', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Department', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Country', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'From Date', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'To Date', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Amount', style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ], rows: paginatedInternational.map(( entry, ) { final forexFromDate = DateFormat( 'dd-MM-yyyy', ).format( DateTime.parse( entry['forex_from_date'], ), ); final forexToDate = DateFormat( 'dd-MM-yyyy', ).format( DateTime.parse( entry['forex_to_date'], ), ); return DataRow( cells: [ DataCell( Text( '${entry['plan_id']}', style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( '${entry['employee_code']}', style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( '${entry['passenger_name']}', style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( '${entry['so_number']}', style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( '${entry['functional_department']}', style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( '${entry['visiting_country']}', style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( forexFromDate, style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( forexToDate, style: GoogleFonts.poppins( fontSize: 12, ), ), ), DataCell( Text( '${entry['amount']}', style: GoogleFonts.poppins( fontSize: 12, ), ), ), ], ); }).toList(), ), ), ), ), ), PaginationControls( currentPage: currentPage, itemsPerPage: itemsPerPage, totalItems: newInternationalData.length, activeColor: layoutColor, onPageChanged: (page) { setState(() { currentPage = page; }); }, onItemsPerPageChanged: (items) { setState(() { itemsPerPage = items; currentPage = 0; }); }, ), ], )); }, ), ), ], ), ), ], ), // SizedBox(height: 15), ], ), ); } Widget buildTitle(bool isDesktop){ return // Left side: Breadcrumb inside a Container (optional) Container( child: BreadcrumbNavigation( isDesktop: isDesktop, breadcrumbItems: [ BreadcrumbItem( title: 'Report List', tooltip: 'Go To Report List', onTap: (context) { // Navigator.pushNamed(context, '/report'); context.go("/report"); } ), BreadcrumbItem( title: 'MIS Forex Report ', ), ], ), ); } Widget buildExports(bool isDesktop){ return Row( children: [ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF114D8B), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: Color(0xFF114D8B), width: 2), ), padding: EdgeInsets.symmetric( horizontal: 20, vertical: 12, ), ), onPressed: handleDownload, child: Row( children: [ Text( "Excel", style: GoogleFonts.poppins( fontSize: isDesktop ? 13 : 11, color: Colors.white, ), ), SizedBox(width: 8), Icon( Icons.file_present_outlined, size: 15, color: Colors.white, ), ], ), ), // SizedBox(width: 10), // ElevatedButton( // style: ElevatedButton.styleFrom( // backgroundColor: Color(0xFF114D8B), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(8), // side: BorderSide(color: Color(0xFF114D8B), width: 2), // ), // padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), // ), // onPressed: () { // // Your PDF export logic here // }, // child: Row( // children: [ // Text( // "PDF", // style: GoogleFonts.poppins( // fontSize: isDesktop ? 13 : 11, // color: Colors.white, // ), // ), // SizedBox(width: 8), // Icon(Icons.picture_as_pdf_outlined, size: 15, color: Colors.white), // ], // ), // ), ], ); } Widget buildFromDateField(bool isDesktop) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "From Date *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: focusStates["from_date"] ?? false, // isDesktop: isDesktop ? MediaQuery.of(context).size.height * 0.51 : 200, isDesktop: isDesktop, width: isDesktop ? null : double.infinity, child: SizedBox( height: 40, child: GestureDetector( onTap: () async { final pickedDate = await showDatePicker( context: context, initialDate: DateTime.now(), initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: DateTime(2000), lastDate: DateTime(2100), ); if (pickedDate != null) { textControllers["from_date"]?.text = DateFormat( 'dd-MM-yyyy', ).format(pickedDate); } }, child: AbsorbPointer( child: TextField( focusNode: focusNodes["from_date"], controller: textControllers["from_date"], 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: const EdgeInsets.symmetric( vertical: 16, ), suffixIcon: const Icon( Icons.calendar_today, size: 16, color: Colors.grey, ), ), ), ), ), ), ), if (errorMessages["from_date"] != null) ...[ SizedBox(height: 5), // Space before error message Text( errorMessages["from_date"]!, style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ); } Widget buildToDateField(bool isDesktop) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "To Date *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: focusStates["to_date"] ?? false, isDesktop: isDesktop, width: isDesktop ? null : double.infinity, child: SizedBox( height: 40, child: GestureDetector( onTap: () async { final fromDateText = textControllers["from_date"]?.text; DateTime? mintoDate; if (fromDateText != null && fromDateText.isNotEmpty) { mintoDate = DateFormat( 'dd-MM-yyyy', ).parse(fromDateText); } final pickedDate = await showDatePicker( context: context, initialDate: DateTime.now(), initialEntryMode: DatePickerEntryMode.calendarOnly, firstDate: mintoDate ?? DateTime(2000), lastDate: DateTime(2100), ); if (pickedDate != null) { textControllers["to_date"]?.text = DateFormat( 'dd-MM-yyyy', ).format(pickedDate); } }, child: AbsorbPointer( child: TextField( focusNode: focusNodes["to_date"], controller: textControllers["to_date"], readOnly: true, style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Select Date", labelStyle: TextStyle( fontSize: 12, color: Colors.grey, ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric( vertical: 16, ), suffixIcon: Icon( Icons.calendar_today, size: 16, color: Colors.grey, ), ), ), ), ), ), ), if (errorMessages["to_date"] != null) ...[ SizedBox(height: 5), // Space before error message Text( errorMessages["to_date"]!, style: const TextStyle(color: Colors.red, fontSize: 12), maxLines: 2, // Allow it to wrap onto two lines overflow: TextOverflow .ellipsis, // Add ellipsis if it still overflows ), ], ], ); } Widget buildSearchButton(bool isDesktop) { return Padding( padding: isDesktop ? const EdgeInsets.only(top: 22) : EdgeInsets.zero, child: SizedBox( width: isDesktop ? null : double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF114D8B), foregroundColor: Colors.white, disabledBackgroundColor: Color(0xFF114D8B), disabledForegroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: Color(0xFF114D8B), width: 2), ), padding: EdgeInsets.symmetric( horizontal: 20, vertical: 12, ), ), onPressed: () { handleSubmit(); }, child: Row( mainAxisSize: MainAxisSize.min, // Ensures content fits nicely children: [ Text( "Search", style: GoogleFonts.poppins( fontSize: isDesktop ? 13 : 11, ), ), SizedBox(width: 8), // spacing between icon and text Icon(Icons.search, size: 15, color: Colors.white), ], ), ), ), ); } }