import 'dart:async'; import 'dart:convert'; import 'dart:core'; import 'dart:html' as html; import 'package:frontend/Screens/allTrips/plan_info_mdl.dart'; import 'package:frontend/data/models/plan.dart'; import 'package:frontend/utils/travelAgent_remarks.dart'; 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 '../../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_popup.dart'; import '../../widgets/popup_listPlan_action.dart'; class TravelAgentListPlans extends StatefulWidget { const TravelAgentListPlans({super.key}); @override _TravelAgentListPlansState createState() => _TravelAgentListPlansState(); } class _TravelAgentListPlansState extends State { final ApiService apiService = ApiService(); late StreamSubscription _popStateListener; int currentPage = 0; int itemsPerPage = 10; String? userId; String? orgId; String? roleUser; String? token; String? TripPlanAction; late bool _dialogShown = false; Color? layoutColor; Color? bodyColor; late Future> futurePlans; List allPlans = []; List filteredPlans = []; TextEditingController searchController = TextEditingController(); @override void initState() { super.initState(); _checkAuthAndLoadData(); checkbackbutton(); // getToken(); // // WidgetsBinding.instance.addPostFrameCallback((_) { // initializeData(); // loadInitialData(); // // // futurePlans.then((plans) { // // setState(() { // // allPlans = plans; // // filteredPlans = plans; // // }); // // }); // }); // futurePlans = fetchPlans(); } 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; } getToken(); initializeData(); loadInitialData(); } void checkbackbutton() async { roleUser = await getRoleUser(); print(roleUser); if (roleUser == "Travel Agent") { print("user"); final prefs = await SharedPreferences.getInstance(); final String? msUserStr = prefs.getString('is_microsoft_user'); final bool msUser = msUserStr?.toLowerCase() == 'true'; print("msUser - $msUser"); html.window.history.pushState(null, '', html.window.location.href); if (!msUser) { _popStateListener = html.window.onPopState.listen((event) { if (!_dialogShown && mounted) { _showBackConfirmationDialog(); } // Re-push to prevent leaving html.window.history.pushState(null, '', html.window.location.href); }); } } } @override void dispose() { _popStateListener.cancel(); // ✅ Remove the browser popstate listener super.dispose(); } Future _logoutAndRedirect(BuildContext context) async { print("logue 0"); await apiService.logout(context); // // Example: clear session or shared preferences // final prefs = await SharedPreferences.getInstance(); // await prefs.clear(); // context.go("/"); print("logue 1"); } void _showBackConfirmationDialog() { if (!mounted) return; _dialogShown = true; showDialog( context: context, builder: (context) => AlertDialog( title: Text("Confirm"), content: Text("Do you want to logout?"), actions: [ TextButton( onPressed: () { Navigator.pop(context); // Close dialog _dialogShown = false; }, child: Text("Cancel"), ), TextButton( onPressed: () async { // Navigator.pop(context); // Close dialog _dialogShown = false; await _logoutAndRedirect(context); }, child: Text("Logout"), ), ], ), ); } void filterPlans(String query) { print("allPlans before filtering: $allPlans"); final lowerQuery = query.toLowerCase(); setState(() { filteredPlans = allPlans.where((plan) { return (plan.planId?.toLowerCase().contains(lowerQuery) ?? false) || (plan.employeeCode?.toLowerCase().contains(lowerQuery) ?? false) || (plan.tripTitle?.toLowerCase().contains(lowerQuery) ?? false) || (plan.userName?.toLowerCase().contains(lowerQuery) ?? false) || (plan.travellerName?.toLowerCase().contains(lowerQuery) ?? false) || (plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) || (plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) || (plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false); }).toList(); }); print("filteredPlans: $filteredPlans"); } 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; }); } Future initializeData() async { token = await getToken(); userId = await getUserId(); orgId = await getOrgId(); roleUser = await getRoleUser(); TripPlanAction = await getTripPlanAction(); if (token == null || userId == null) { print("Token or USerId missing"); return; } else { setState(() { futurePlans = fetchPlans(); }); // Wait for futurePlans to be fetched and update allPlans futurePlans.then((plans) { setState(() { allPlans = plans; // Set allPlans after the fetch is complete filteredPlans = allPlans; // You can update filteredPlans too if needed }); }); } } void refresh() { print("Refresj"); setState(() { futurePlans = fetchPlans(); }); // Wait for futurePlans to be fetched and update allPlans futurePlans.then((plans) { setState(() { allPlans = plans; // Set allPlans after the fetch is complete filteredPlans = allPlans; // You can update filteredPlans too if needed }); }); } 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'); } // Fetch API Data Future> fetchPlans() async { late String apiUrldata; apiUrldata = '$apiUrl/api/plans/findTravelAgentPlanList?org_id=$orgId&user_id=$userId'; if (token == null) { throw Exception('Token not found. Please log in.'); } final response = await http.get( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', // Add token here 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, ); if (response.statusCode == 200) { final data = json.decode(response.body); // List plansJson = []; List plansJson = data['data']; return plansJson.map((json) => Plan.fromJson(json)).toList(); } else if (response.statusCode == 403) { print("403-FORB"); await apiService.logout(context); return []; // throw Exception('Failed to load users'); } else { throw Exception('Failed to load plans'); } } Future postPlanData(planData, planId) async { final String apiUrldata = '$apiUrl/api/plans/createOrEditPlan'; final token = await getToken(); // Fetch token if (token == null) { throw Exception('Token not found. Please log in.'); } planData['is_active'] = "0"; print("POSTPlanTesting------- $planData"); // Add plan_id for update try { final response = await http.post( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, body: jsonEncode(planData), // Convert map to JSON ); if (response.statusCode == 200) { print("Plan Deleted successfully!"); print("Response: ${response.body}"); initializeData(); } else if (response.statusCode == 403) { print("403-FORB"); await apiService.logout(context); return null; // throw Exception('Failed to load users'); } else { print("Failed to submit plan. Status: ${response.statusCode}"); print("Error: ${response.body}"); } } catch (e) { print(" Error submitting plan: $e"); } } void deletePlan(String planId) async { bool confirmed = await apiService.showCancelConfirmationDialog( context, layoutColor, ); if (confirmed) { try { Map planData = await ApiService().getViewPlan( planId, context, ); print("ViewAAA - $planData"); refresh(); // postPlanData(planData, planId); } catch (e) { print("Error fetching plan: $e"); } } else { print("User cancelled"); } } Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), // appBar: isDesktop ? null : const CustomAppBar(title: 'Home'), // drawer: isDesktop ? null : CustomDrawer(isDesktop: false), 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), Expanded(child: buildGroupListLayout(isDesktop)), ], ), ), ); }, ); } Widget buildGroupListLayout(bool isDesktop) { return Container( // decoration: BoxDecoration( // // color: Colors.amber, // // color: bodyColor, // color: Color(0xFFE1F5FE), // border: Border.all( // // color: Color(0xFFF7F7FB), // color: Colors.white, // width: 3.5)), child: buildTableLayout(isDesktop), ); } Widget buildTableLayout(isDesktop) { // String _formatDate(String rawDate) { // try { // final dateTime = DateTime.parse(rawDate); // return DateFormat('dd,MMM yyyy hh:m a').format(dateTime); // } catch (e) { // return rawDate; // fallback if parsing fails // } // } String _formatDate(String rawDate) { try { final dateTime = DateTime.parse(rawDate); return DateFormat( 'dd, MMM yyyy HH:mm', ).format(dateTime); // 24-hour format } catch (e) { return rawDate; // fallback if parsing fails } } return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), height: isDesktop ? MediaQuery.of(context).size.height * 0.98 : MediaQuery.of(context).size.height, decoration: BoxDecoration( border: isDesktop ? Border.all( width: 2, color: Colors.white, // color: Color(0xFFF7F7FB), ) : null, color: isDesktop ? Colors.white : Color(0xFFFCFCFC), // color: Color(0xFFF7F7FB), // color: Colors.amber, ), child: Padding( padding: isDesktop ? const EdgeInsets.only( top: 15, bottom: 15, left: 20, right: 20, ) : const EdgeInsets.only(top: 15, bottom: 15, left: 5, right: 5), child: Container( // padding: const EdgeInsets.all(10.0), color: isDesktop ? Colors.white : Color(0xFFFCFCFC), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Divider( // thickness: 0.2, // how "thick" the line is // color: Colors.grey, // optional // ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.only(left: 14.0), child: Row( children: [ Text( 'Trips', style: GoogleFonts.poppins( fontSize: isDesktop ? 16 : 14, fontWeight: FontWeight.w600, color: Colors.black, ), // style: TextStyle( // fontFamily: "Inter", // fontSize: isDesktop ? 16 : 14, // fontWeight: FontWeight.w600, // color: Color(0xFF212121)) ), ], ), ), Spacer(), if (isDesktop) Container( width: MediaQuery.of(context).size.width * 0.2, height: 40, child: TextField( controller: searchController, onChanged: filterPlans, 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: TextStyle(fontSize: 12, fontFamily: "Inter"), ), ), // SizedBox(width: 16), // Spacer(), // ElevatedButton( // style: ElevatedButton.styleFrom( // foregroundColor: Colors.white, // backgroundColor: Colors.blueAccent, // ), // onPressed: () { // context.go('/createPlan', extra: { // 'orgId': orgId, // }); // if (!isDesktop) Navigator.pop(context); // }, // child: Row( // children: [ // Icon(Icons.add_circle, color: Colors.white), // SizedBox(width: 5), // Text('NewPlan'), // // ], // ), // ), ], ), if (!isDesktop) const SizedBox(height: 10), if (!isDesktop) Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: MediaQuery.of(context).size.width * 0.85, height: 35, child: TextField( controller: searchController, onChanged: filterPlans, 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), ), ), ], ), const SizedBox(height: 10), FutureBuilder>( future: futurePlans, builder: (context, snapshot) { final adjHgt = MediaQuery.of(context).size.height; if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError || !snapshot.hasData || snapshot.data!.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ // SizedBox(height: 20), // Icon(Icons.error_outline, // color: Colors.redAccent, size: 60), // SizedBox(height: 1), // Text("Oops!", // style: TextStyle( // fontSize: 22, // fontWeight: FontWeight.bold, // color: Colors.redAccent)), isDesktop ? SizedBox( width: MediaQuery.of(context).size.width * 5.5, ) : SizedBox.shrink(), SizedBox(height: adjHgt / 4), Text( " No Trips Found", textAlign: TextAlign.center, style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w500, color: Colors.black54, ), ), SizedBox(height: 10), // Text("Please Create Trip", // textAlign: TextAlign.center, // style: TextStyle( // fontFamily: "Inter", // fontSize: 12, // color: Colors.grey)), // SizedBox(height: 20), ], ), ), ); } // List plans = snapshot.data!; // List plans = // filteredPlans.isNotEmpty ? filteredPlans : allPlans; List plans = searchController.text.isEmpty ? allPlans : filteredPlans; plans.sort( (a, b) => int.parse(b.planId).compareTo(int.parse(a.planId)), ); List paginatedPlans = plans .skip(currentPage * itemsPerPage) .take(itemsPerPage) .toList(); Widget table = LayoutBuilder( builder: (context, constraints) { double minWidth = isDesktop ? constraints.maxWidth : 1300; return ConstrainedBox( constraints: BoxConstraints(minWidth: minWidth), child: DataTable( dividerThickness: 0.5, columnSpacing: isDesktop ? 24.0 : 16.0, border: TableBorder( horizontalInside: BorderSide( width: 0.5, color: Colors.grey.shade200, ), ), columns: [ DataColumn( label: Text( 'Trip ID', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Trip Name', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Emp Code', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Traveller', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Trip Type', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Created On', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Status', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), DataColumn( label: Text( 'Actions', style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.w600, ), ), ), ], rows: paginatedPlans.map((plan) { return DataRow( cells: [ DataCell( Text( plan.planId, style: TextStyle( fontSize: 13, fontFamily: "Inter", ), ), ), DataCell( SizedBox( width: 130, child: Text( plan.tripTitle, style: TextStyle( fontSize: 13, fontFamily: "Inter", ), softWrap: true, maxLines: 2, // overflow: TextOverflow.ellipsis, ), ), ), DataCell( Text( plan.employeeCode ?? " - ", style: TextStyle( fontSize: 13, fontFamily: "Inter", ), ), ), DataCell( Text( plan.userName.isNotEmpty ? plan.userName : plan.travellerName, style: TextStyle( fontSize: 13, fontFamily: "Inter", ), ), ), DataCell( Text( plan.tripType, style: TextStyle( fontSize: 13, fontFamily: "Inter", ), ), ), DataCell( Text( _formatDate(plan.createdOn), // plan.createdOn, style: TextStyle( fontSize: 13, fontFamily: "Inter", ), ), ), DataCell( Container( padding: const EdgeInsets.all(3), // width: // 150, // Set your desired fixed size (equal width and height) width: double .infinity, // Set your desired fixed size (equal width and height) height: 25, alignment: Alignment.center, decoration: BoxDecoration( color: getStatusColor( plan.statusValue, ), borderRadius: BorderRadius.circular( 10, ), ), child: Text( plan.statusValue, textAlign: TextAlign.center, style: TextStyle( color: getStatusTextColor( plan.statusValue, ), fontSize: 12, fontFamily: "Inter", fontWeight: FontWeight.w400, ), ), ), ), DataCell( Row( children: [ PopupMenuButton( color: Colors.white, padding: EdgeInsets.zero, offset: Offset(0, 30), icon: Icon( Icons.more_vert, color: Color(0xFF475569), ), itemBuilder: (context) => [ CustomPopupMenuEntry( child: Container( padding: EdgeInsets.symmetric( horizontal: 8, vertical: 8, ), child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment .center, children: [ IconButton( icon: Icon( Icons .remove_red_eye, color: Color( 0xFF475569, ), size: 16, ), onPressed: () { Navigator.pop( context, ); // Close popup manually ApiService() .viewPlanTravelAgent( context, plan.planId, isViewMode: true, ); }, ), // IconButton( // icon: Image.asset( // 'assets/images/IconsImg/edit.png', // width: 20, // height: 15), // onPressed: () { // Navigator.pop(context); // ApiService.viewPlan( // context, plan.planId, // isViewMode: false); // }, // ), IconButton( icon: Icon( Icons .cancel_rounded, size: 18, ), onPressed: () { Navigator.pop( context, ); deletePlan( plan.planId, ); }, ), IconButton( icon: Icon( Icons.download, color: Color( 0xFF114D8B, ), size: 18, ), onPressed: () { Navigator.pop( context, ); apiService .getPdfDownload( context, plan.planId, ); }, ), if (plan.statusValue == "Approved" && plan.forexId != null && plan.forexId != '') IconButton( icon: Icon( Icons .monetization_on_outlined, color: Color( 0xFF475569, ), size: 18, ), tooltip: 'Download Forex PDF', onPressed: () { Navigator.pop( context, ); apiService .getForexPdfDownload( context, plan.forexId, ); }, ), IconButton( icon: const Icon( Icons.comment, color: Color( 0xFF475569, ), size: 11, ), onPressed: () { showDialog( context: context, builder: ( context, ) => CommentModal( // planId: plan.planId, planId: plan.planId .toString(), layoutColorForUser: layoutColor!, role: "Travel Agent", ), ); }, ), IconButton( icon: const Icon( Icons .info_outlined, color: Color( 0xFF475569, ), size: 18, ), tooltip: 'Trip Info', onPressed: () { showDialog( context: context, builder: ( context, ) => TripInformation( // planId: plan.planId, planId: plan.planId .toString(), layoutColorForUser: layoutColor!, ), ); }, ), ], ), ), ), ], ), ], ), ), // DataCell(Row(children: [ // IconButton( // icon: const Icon( // Icons.remove_red_eye, // color: Color(0xFF475569), // size: 18, // ), // onPressed: () => ApiService.viewPlan( // context, plan.planId, // isViewMode: true)), // GestureDetector( // onTap: () => ApiService.viewPlan( // context, plan.planId, // isViewMode: false), // child: Image.asset( // 'assets/images/IconsImg/edit.png', // width: 20, // height: 15), // ), // SizedBox( // width: 5, // ), // GestureDetector( // onTap: () => deletePlan(plan.planId), // child: Image.asset( // 'assets/images/IconsImg/delete.png', // width: 20, // height: 15), // ), // IconButton( // icon: const Icon( // Icons.download, // color: Color(0xFF475569), // size: 18, // ), // onPressed: () { // apiService.getPdfDownload(plan.planId); // }), // ])), ], ); }).toList(), ), ); }, ); Widget buildMobileCardView(List paginatedPlans) { return ListView.builder( itemCount: paginatedPlans.length, itemBuilder: (context, index) { final plan = paginatedPlans[index]; return Card( color: Colors.white, margin: EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 3, child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Status and Employee Code Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( padding: EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: getStatusColor(plan.statusValue), borderRadius: BorderRadius.circular(8), ), child: Text( plan.statusValue, style: TextStyle( color: getStatusTextColor( plan.statusValue, ), fontSize: 10, fontWeight: FontWeight.w600, ), ), ), PlanPopupMenu( plan: plan, deletePlan: deletePlan, apiService: apiService, layoutColor: layoutColor, ), ], ), SizedBox(height: 2), // Trip Id and Trip Name Row( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( ' ${plan.tripTitle}', style: TextStyle( fontSize: 12, fontFamily: "Inter", fontWeight: FontWeight.bold, ), ), ], ), ], ), SizedBox(height: 2), // Type and Created On Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( ' ${plan.tripType}', style: TextStyle( fontSize: 9, color: Colors.black87, fontFamily: "Inter", ), ), ], ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${_formatDate(plan.createdOn)}', style: TextStyle( fontSize: 9, color: Colors.black87, fontFamily: "Inter", ), ), ], ), ], ), SizedBox(height: 3), // Name Row( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( plan.userName.isNotEmpty ? '${plan.userName}' : '${plan.travellerName}', style: TextStyle( fontSize: 9, fontFamily: "Inter", color: Colors.black87, ), ), ], ), Spacer(), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( plan.employeeCode ?? 'No Data', style: TextStyle( fontSize: 9, fontFamily: "Inter", color: Colors.black87, ), ), ], ), ], ), // Actions // Actions ], ), ), ); }, ); } return Expanded( child: Column( // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: isDesktop ? (searchController.text.isNotEmpty && filteredPlans.isEmpty ? Center( child: Text( "No matches found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, ), ), ) : SingleChildScrollView( scrollDirection: Axis.vertical, child: table, )) : (searchController.text.isNotEmpty && filteredPlans.isEmpty ? Center( child: Text( "No matches found", style: GoogleFonts.poppins( fontSize: 14, color: Colors.grey, ), ), ) : buildMobileCardView(paginatedPlans)), // child: isDesktop // ? SingleChildScrollView( // scrollDirection: Axis.vertical, // child: table, // <-- your existing table // ) // : buildMobileCardView(paginatedPlans), ), PaginationControls( currentPage: currentPage, itemsPerPage: itemsPerPage, totalItems: plans.length, activeColor: layoutColor, // your theme color onPageChanged: (page) { setState(() { currentPage = page; }); }, onItemsPerPageChanged: (items) { setState(() { itemsPerPage = items; currentPage = 0; }); }, ), ], ), ); }, ), ], ), ), ), ); } // Helper functions for colors Color getStatusColor(String status) { if (status == "Partially Approved") return Colors.yellow.shade100; if (status == "Approved") return Colors.green.shade100; if (status == "Completed") return Colors.green.shade500; if (status == "Rejected") return Colors.red.shade100; return Colors.grey.shade100; } Color getStatusTextColor(String status) { if (status == "Partially Approved" || status == "Approved" || status == "Rejected") { return Colors.black; } else if (status == "Completed") { return Colors.white; } return Colors.grey; } }