From d99d9433ecb6566ff8cb7bb0e95b8c64820a1d04 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Wed, 21 May 2025 13:09:31 +0530 Subject: [PATCH 1/2] Template List --- lib/Screens/forex/forex_list.dart | 41 +- lib/Screens/myTemplates/templatesList.dart | 780 ++++++++++++++++++++- lib/routes/custom_router.dart | 2 +- lib/services/apiService.dart | 2 +- 4 files changed, 813 insertions(+), 12 deletions(-) diff --git a/lib/Screens/forex/forex_list.dart b/lib/Screens/forex/forex_list.dart index 4538554..b6112cc 100644 --- a/lib/Screens/forex/forex_list.dart +++ b/lib/Screens/forex/forex_list.dart @@ -775,10 +775,43 @@ class ForexDataListState extends State { fontWeight: FontWeight.w700), ), - UserActionsMenu( - user: forex, - getUserDetails: (id) => - apiService.getSingleUser(id), + GestureDetector( + child: Image.asset( + 'assets/images/IconsImg/edit.png', + width: 20, + height: 15), + onTap: () async { + // final userId = getUserId(user['user_id']); + // final usersData = await getUserDetails(userId); + // + final forexId = int.tryParse( + forex['forex_perdiem_id'] + .toString()); + + if (forexId != null) { + print("ForexId -- $forexId"); + final data = await apiService + .getForexDetailsFind(forexId); + print("ForexId -- $data"); + + showDialog( + context: context, + builder: (context) => ForexData( + isDesktop: isDesktop, + forexId: + forexId, // Pass the ID + forexData: data, + layoutColor: layoutColor!, + // fetchGetForex: fetchGetForex, + fetchGetForex: refreshData, + // role: + // "Travel Agent" + ), + ); + } else { + print("Invalid Forex ID"); + } + }, ), // PopupMenuButton( // color: Colors.white, diff --git a/lib/Screens/myTemplates/templatesList.dart b/lib/Screens/myTemplates/templatesList.dart index bfb30a1..f5b5e66 100644 --- a/lib/Screens/myTemplates/templatesList.dart +++ b/lib/Screens/myTemplates/templatesList.dart @@ -1,6 +1,7 @@ import 'dart:convert'; + +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:frontend/utils/auth_utils.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -11,21 +12,288 @@ import '../../config/apiUrl.dart'; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; import '../../services/apiService.dart'; +import '../../utils/auth_utils.dart'; import '../../utils/pagination.dart'; -import '../../widgets/custom_popup.dart'; import '../../widgets/popup_userList_action.dart'; -class templatesList extends StatefulWidget { +class TemplatesList extends StatefulWidget { + const TemplatesList({super.key}); + @override - _templatesListState createState() => _templatesListState(); + TemplatesListState createState() => TemplatesListState(); } -class _templatesListState extends State { +class TemplatesListState extends State { + // final GlobalKey forexListKey = + // GlobalKey(); + final ApiService apiService = ApiService(); + late Future> futureTemplates; + + late Map userSingleData; + List? apiCountryData; + String? selectedUserId; + String? orgId; + + Color? layoutColor; + Color? bodyColor; + + List allTemplate = []; + List filteredTemplates = []; + TextEditingController searchController = TextEditingController(); + + int currentPage = 0; + int itemsPerPage = 10; @override void initState() { super.initState(); + futureTemplates = fetchGetForex(); + + futureTemplates.then((users) { + setState(() { + allTemplate = users; + print("AlL tEMPLATESNIT - $allTemplate"); + }); + }); + + WidgetsBinding.instance.addPostFrameCallback((_) { + loadInitialData(); + }); + + // futurePlans = fetchPlans(); + } + + Future> refreshData() { + print("Calling Refresh Data"); + + futureTemplates = fetchGetForex(); + + return futureTemplates.then((users) { + setState(() { + allTemplate = users; + }); + return users; + }); + } + + 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; + }); + } + + String formatTemplateName(String input) { + return input + .split('_') // split by underscore + .map((word) => word.isNotEmpty + ? '${word[0].toUpperCase()}${word.substring(1)}' + : '') + .join(' '); + } + + String getPlaceholderNames(String? raw) { + if (raw == null || raw.isEmpty) return ''; + + try { + final List decoded = json.decode(raw); + final List values = decoded + .map((e) => e['value'].toString().replaceAll('%', '')) + .toList(); + return values.join(', '); + } catch (e) { + return 'Invalid placeholder'; + } + } + + Future getToken() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('auth_token'); + } + + Future> fetchGetForex() async { + orgId = await getOrgId(); + // final String apiUrlData = '$apiUrl/api/getForexPerdiemList'; + final String apiUrlData = '$apiUrl/api/template?org_id=${orgId}'; + + final String? token = await getToken(); + + print("Fetch Users"); + print("TOEKRWE: $token"); + + if (token == null) { + throw Exception('Token not found. Please log in.'); + } + + final response = await http.get( + Uri.parse(apiUrlData), + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + + print("TemplateDATA--- $data"); + return data['data']; // Returning raw JSON list + } else { + throw Exception('Failed to load users'); + } + } + + void handleDelete(userId) { + print("handDel - $userId"); + } + + Future createTemplateData( + Map userData, String userId, String newStatus) async { + final uri = Uri.parse('$apiUrl/api/users/update/$userId'); + + final String? token = await getToken(); + if (token == null) { + throw Exception('Token not found. Please log in.'); + } + + // Use MultipartRequest (POST only) + final request = http.MultipartRequest('POST', uri); + request.headers['Authorization'] = 'Bearer $token'; + + // If updating, spoof the method Laravel-style + + request.fields['_method'] = 'PUT'; + request.fields['user_id'] = userId; + + print("STatus 2 - $newStatus"); + + // Add all non-null and non-empty user data fields + userData.forEach((key, value) { + if (value != null && value.toString().trim().isNotEmpty) { + request.fields[key] = value.toString(); + } + }); + + request.fields['is_active'] = newStatus; + + print("🚀 Sending request with fields: ${request.fields}"); + + try { + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + print("Response status: ${response.statusCode}"); + print("Response body: ${response.body}"); + + if (response.statusCode == 200 || response.statusCode == 201) { + print("✅ User Status submitted successfully! "); + print("📨 Response: ${response.body}"); + + refreshUserList(); + } else { + print("❌ Submission failed. Status: ${response.statusCode}"); + print("📨 Body: ${response.body}"); + } + } catch (e) { + print("🔥 Error submitting user: $e"); + } + } + + void handleToggleUserStatus(String userId, String currentStatus, + Map userData) async { + print("Toggling user status - $userId (Current: $currentStatus)"); + + final String apiUrlData = + '$apiUrl/api/users/update/$userId'; // API for updating user + final String? token = await getToken(); + + if (token == null) { + print("Error: Token not found"); + return; + } + + // Toggle status: If active ("1"), set to inactive ("0"); otherwise, activate ("1") + String newStatus = (currentStatus == "1") ? "0" : "1"; + + print("STatus 1 - $newStatus"); + + createTemplateData(userData, userId, newStatus); + + // try { + // final response = await http.put( + // Uri.parse(apiUrlData), + // headers: { + // 'Authorization': 'Bearer $token', + // 'Content-Type': 'application/json', + // }, + // body: jsonEncode({ + // "is_active": newStatus // Set new status dynamically + // }), + // ); + // + // if (response.statusCode == 200) { + // print("User status updated successfully to $newStatus!"); + // refreshUserList(); // Refresh users list after update + // } else { + // print("Failed to update user status. Status: ${response.statusCode}"); + // print("Error: ${response.body}"); + // } + // } catch (e) { + // print("Error updating user status: $e"); + // } + } + +// Refresh user list after update + void refreshUserList() { + setState(() { + futureTemplates = fetchGetForex(); // Re-fetch users after status update + // Wait for futurePlans to be fetched and update allPlans + }); + } + + void filterTemplates(String query) { + print("Filtering by query: $query"); + final lowerQuery = query.toLowerCase(); + + setState(() { + filteredTemplates = allTemplate.where((user) { + // Match template_name + final templateName = + (user['template_name'] ?? '').toString().toLowerCase(); + final matchesTemplate = templateName.contains(lowerQuery); + + // Match placeholder values + final placeholderRaw = user['placeholder']; + bool matchesPlaceholder = false; + + if (placeholderRaw != null && placeholderRaw is String) { + try { + final List decoded = json.decode(placeholderRaw); + final List placeholderValues = decoded + .map((e) => + e['value'].toString().replaceAll('%', '').toLowerCase()) + .toList(); + + matchesPlaceholder = + placeholderValues.any((value) => value.contains(lowerQuery)); + } catch (e) { + // ignore invalid placeholder format + } + } + + return matchesTemplate || matchesPlaceholder; + }).toList(); + }); + + print("Filtered results: $filteredTemplates"); } @override @@ -35,6 +303,8 @@ class _templatesListState extends State { return Scaffold( backgroundColor: Color(0xFFf5f5f5), + // appBar: isDesktop ? null : const CustomAppBar(title: 'User Management'), + // drawer: isDesktop ? null : CustomDrawer(isDesktop: false), appBar: CustomAppBar(isDesktop: isDesktop), drawer: CustomDrawer(isDesktop: false), body: Padding( @@ -47,10 +317,508 @@ class _templatesListState extends State { ) : EdgeInsets.all(0), child: Row( - children: [Text("Template Lsit")], + children: [ + // if (isDesktop) CustomDrawer(isDesktop: true), + // const Expanded(child: Center(child: Text("User Page Content"))), + Expanded(child: buildGroupList(isDesktop)), + ], ), ), ); }); } + + Widget buildGroupList(bool isDesktop) { + return Container( + margin: isDesktop ? const EdgeInsets.only(top: 10.0, bottom: 10.0) : null, + padding: const EdgeInsets.all(1), + decoration: BoxDecoration( + color: isDesktop ? Colors.white : Color(0xFFFCFCFC), + ), + // decoration: BoxDecoration( + // // color: Colors.amber, + // // color: bodyColor, + // color: Color(0xFFE1F5FE), + // border: Border.all( + // color: Colors.white, + // // color: Color(0xFFF7F7FB), + // width: 3.5)), + child: buildUserTable(isDesktop), + ); + } + + Widget buildUserTable(bool isDesktop) { + return Container( + // margin: isDesktop + // ? EdgeInsets.all(10.0) + // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), + // padding: const EdgeInsets.all(10), + height: isDesktop + ? MediaQuery.of(context).size.height * 0.98 + : MediaQuery.of(context).size.height, + + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Container( + color: Colors.white, + padding: const EdgeInsets.all(10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // Divider( + // thickness: 0.2, // how "thick" the line is + // color: Colors.grey, // optional + // ), + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Text( + 'Templates', + style: GoogleFonts.poppins( + fontSize: isDesktop ? 16 : 14, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), + ], + ), + if (isDesktop) + SizedBox( + width: MediaQuery.of(context).size.width * 0.23, + ), + + if (isDesktop) + Container( + width: MediaQuery.of(context).size.width * 0.2, + height: 40, + child: TextField( + controller: searchController, + onChanged: filterTemplates, + 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, + ), + ), + ), + // SizedBox(width: 16), + Spacer(), + + 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: () async {}, + child: Row( + mainAxisSize: + MainAxisSize.min, // Ensures content fits nicely + children: [ + Text( + "Add Templates", + style: GoogleFonts.poppins( + fontSize: isDesktop ? 13 : 11, + ), + ), + SizedBox(width: 8), // spacing between icon and text + Icon( + Icons.add_circle_outline_rounded, + size: 15, + color: Colors.white, + ), + ], + ), + ), + ], + ), + + if (!isDesktop) + SizedBox( + height: 5, + ), + isDesktop + ? SizedBox.shrink() + : Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.8, + height: 35, + child: TextField( + controller: searchController, + onChanged: filterTemplates, + 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, + ), + ), + ), + // SizedBox(width: 16), + ], + ), + const SizedBox(height: 10), + FutureBuilder>( + future: futureTemplates, + builder: (context, snapshot) { + 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: [ + // const Icon(Icons.error_outline, + // color: Colors.redAccent, size: 60), + // const SizedBox(height: 16), + // Text( + // "Oops!", + // style: GoogleFonts.poppins( + // fontSize: 20, + // fontWeight: FontWeight.bold, + // color: Colors.redAccent), + // ), + const SizedBox(height: 8), + Text( + "No Templates Available ", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.grey), + ), + const SizedBox(height: 20), + Text( + "Please Create Templates", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + fontSize: 16, color: Colors.grey), + ), + const SizedBox(height: 20), + ], + ), + ), + ); + } + + List templates = filteredTemplates.isNotEmpty + ? filteredTemplates + : allTemplate; + + // users.sort((a, b) { + // DateTime dateA = DateTime.parse(a['created_on']); + // DateTime dateB = DateTime.parse(b['created_on']); + // + // return dateB + // .compareTo(dateA); // Descending: newest first + // }); + + templates.sort((a, b) { + try { + DateTime dateA = + DateTime.parse(a['created_at'] ?? '2000-01-01'); + DateTime dateB = + DateTime.parse(b['created_at'] ?? '2000-01-01'); + return dateB.compareTo(dateA); + } catch (e) { + return 0; // If parsing fails, consider them equal + } + }); + + List paginatedTemplates = templates + .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( + 'Template Name', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), + DataColumn( + label: Text( + 'Attributes', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), + DataColumn( + label: Text( + 'Actions', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), + ], + rows: paginatedTemplates.map((forex) { + String forexId = forex['template_id'] + .toString(); // Get user ID + bool isSelected = selectedUserId == forexId; + + return DataRow(cells: [ + DataCell(Text( + // "${forex['template_name'] ?? ''}", + formatTemplateName( + forex['template_name'] ?? ''), + // Text("{forex['template_name'] ?? ''}", + style: TextStyle( + fontSize: 13, + fontFamily: "Inter", + ))), + DataCell(Text( + getPlaceholderNames(forex['placeholder']), + style: TextStyle( + fontSize: 13, + fontFamily: "Inter", + ))), + DataCell( + // UserActionsMenu( + // user: forex, + // getUserDetails: (id) => + // apiService.getSingleUser(id), + // ), + GestureDetector( + child: Image.asset( + 'assets/images/IconsImg/edit.png', + width: 20, + height: 15), + onTap: () async { + // final userId = getUserId(user['user_id']); + // final usersData = await getUserDetails(userId); + // + final forexId = int.tryParse( + forex['forex_perdiem_id'] + .toString()); + + if (forexId != null) { + print("ForexId -- $forexId"); + final data = await apiService + .getForexDetailsFind(forexId); + print("ForexId -- $data"); + } else { + print("Invalid Forex ID"); + } + }, + ), + ), + ]); + }).toList(), + ), + ); + }, + ); + + Widget buildMobileCardView(List paginatedUser) { + return ListView.builder( + itemCount: paginatedUser.length, + itemBuilder: (context, index) { + final forex = paginatedUser[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: [ + Text( + // forex['template_name'] ?? 'N/A', + formatTemplateName( + forex['template_name'] ?? ''), + style: GoogleFonts.poppins( + fontSize: 10, + color: Colors.black87, + fontWeight: FontWeight.w700), + ), + UserActionsMenu( + user: forex, + getUserDetails: (id) => + apiService.getSingleUser(id), + ), + ], + ), + + SizedBox(height: 2), + // Trip Id and Trip Name + Row( + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + getPlaceholderNames( + forex['placeholder']), + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black87, + fontWeight: FontWeight.w500), + ), + ], + ), + ], + ), + + // Actions + // Actions + ], + ), + ), + ); + }, + ); + } + + return Expanded( + child: Column( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: isDesktop + ? (searchController.text.isNotEmpty && + filteredTemplates.isEmpty + ? Center( + child: Text( + "No matches found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey), + ), + ) + : SingleChildScrollView( + scrollDirection: Axis.vertical, + child: table, + )) + : (searchController.text.isNotEmpty && + filteredTemplates.isEmpty + ? Center( + child: Text( + "No matches found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey), + ), + ) + : buildMobileCardView( + paginatedTemplates)), + ), + // Expanded( + // child: isDesktop + // ? SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: table, // <-- your existing table + // ) + // : buildMobileCardView(paginatedUser), + // ), + PaginationControls( + currentPage: currentPage, + itemsPerPage: itemsPerPage, + totalItems: templates.length, + activeColor: layoutColor, // your theme color + onPageChanged: (page) { + setState(() { + currentPage = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage = items; + currentPage = 0; + }); + }, + ), + ], + ), + ); + }, + ) + ]), + )), + ); + } } diff --git a/lib/routes/custom_router.dart b/lib/routes/custom_router.dart index 733afb5..940e033 100644 --- a/lib/routes/custom_router.dart +++ b/lib/routes/custom_router.dart @@ -104,7 +104,7 @@ final GoRouter router = GoRouter( ), GoRoute( path: '/templateList', - builder: (context, state) => templatesList(), + builder: (context, state) => TemplatesList(), ), GoRoute( path: '/template', diff --git a/lib/services/apiService.dart b/lib/services/apiService.dart index 5f3865f..a7fb98c 100644 --- a/lib/services/apiService.dart +++ b/lib/services/apiService.dart @@ -734,7 +734,7 @@ class ApiService { } Future> getForexDetailsFind(int userId) async { - print('Single USer 1 - $userId'); + print('Single Forez 1 - $userId'); // final String apiUrldata = '$apiUrl/api/users/find/$userId'; final String apiUrldata = From 3be2f695c6fb61f0407227bbd4800976b6fa77f0 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Wed, 21 May 2025 14:21:52 +0530 Subject: [PATCH 2/2] Header Icons , Forex Search --- lib/Screens/forex/forex_list.dart | 86 ++++++++++++++++++++++++------- lib/routes/custom_appBar.dart | 4 +- 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/lib/Screens/forex/forex_list.dart b/lib/Screens/forex/forex_list.dart index b6112cc..58dae9b 100644 --- a/lib/Screens/forex/forex_list.dart +++ b/lib/Screens/forex/forex_list.dart @@ -282,21 +282,43 @@ class ForexDataListState extends State { }); } - void filterUsers(String query) { + void filterForex1(String query) { print("allUsers before filtering: $query"); final lowerQuery = query.toLowerCase(); setState(() { - filteredForex = allForex.where((user) { - return (user['first_name']?.toLowerCase().contains(lowerQuery) ?? + filteredForex = allForex.where((forex) { + return (forex['country_code']?.toLowerCase().contains(lowerQuery) ?? false) || - (user['last_name']?.toLowerCase().contains(lowerQuery) ?? false) || - (user['email']?.toLowerCase().contains(lowerQuery) ?? false) || - (user['role_value']?.toLowerCase().contains(lowerQuery) ?? false); + (forex['country_name']?.toLowerCase().contains(lowerQuery) ?? + false) || + (forex['currency']?.toLowerCase().contains(lowerQuery) ?? false) || + (forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ?? + false); }).toList(); }); print("filteredPlans: $filteredForex"); } + void filterForex(String query) { + print("allForex before filtering: $query"); + final lowerQuery = query.toLowerCase(); + setState(() { + filteredForex = allForex.where((forex) { + final isActiveStatus = + forex['is_active'] == "1" ? "active" : "inactive"; + return (forex['country_code']?.toLowerCase().contains(lowerQuery) ?? + false) || + (forex['country_name']?.toLowerCase().contains(lowerQuery) ?? + false) || + (forex['currency']?.toLowerCase().contains(lowerQuery) ?? false) || + (forex['perdiem_amount']?.toLowerCase().contains(lowerQuery) ?? + false) || + (isActiveStatus.contains(lowerQuery)); + }).toList(); + }); + print("filteredForex: $filteredForex"); + } + @override Widget build(BuildContext context) { return ResponsiveBuilder(builder: (context, sizingInfo) { @@ -396,7 +418,7 @@ class ForexDataListState extends State { height: 40, child: TextField( controller: searchController, - onChanged: filterUsers, + onChanged: filterForex, decoration: InputDecoration( hintText: "Search ...", hintStyle: TextStyle( @@ -490,7 +512,7 @@ class ForexDataListState extends State { height: 35, child: TextField( controller: searchController, - onChanged: filterUsers, + onChanged: filterForex, decoration: InputDecoration( hintText: "Search ...", hintStyle: TextStyle( @@ -571,10 +593,10 @@ class ForexDataListState extends State { ); } - List users = + List forex = filteredForex.isNotEmpty ? filteredForex : allForex; - users.sort((a, b) { + forex.sort((a, b) { DateTime dateA = DateTime.parse(a['created_on']); DateTime dateB = DateTime.parse(b['created_on']); @@ -582,7 +604,7 @@ class ForexDataListState extends State { .compareTo(dateA); // Descending: newest first }); - List paginatedUser = users + List paginatedForex = forex .skip(currentPage * itemsPerPage) .take(itemsPerPage) .toList(); @@ -645,7 +667,7 @@ class ForexDataListState extends State { fontWeight: FontWeight.w600), )), ], - rows: paginatedUser.map((forex) { + rows: paginatedForex.map((forex) { String forexId = forex['forex_perdiem_id'] .toString(); // Get user ID bool isSelected = selectedUserId == forexId; @@ -958,16 +980,44 @@ class ForexDataListState extends State { children: [ Expanded( child: isDesktop - ? SingleChildScrollView( - scrollDirection: Axis.vertical, - child: table, // <-- your existing table - ) - : buildMobileCardView(paginatedUser), + ? (searchController.text.isNotEmpty && + filteredForex.isEmpty + ? Center( + child: Text( + "No matches found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey), + ), + ) + : SingleChildScrollView( + scrollDirection: Axis.vertical, + child: table, + )) + : (searchController.text.isNotEmpty && + filteredForex.isEmpty + ? Center( + child: Text( + "No matches found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey), + ), + ) + : buildMobileCardView(paginatedForex)), ), + // Expanded( + // child: isDesktop + // ? SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: table, // <-- your existing table + // ) + // : buildMobileCardView(paginatedUser), + // ), PaginationControls( currentPage: currentPage, itemsPerPage: itemsPerPage, - totalItems: users.length, + totalItems: forex.length, activeColor: layoutColor, // your theme color onPageChanged: (page) { setState(() { diff --git a/lib/routes/custom_appBar.dart b/lib/routes/custom_appBar.dart index e6c3da8..88b8ff6 100644 --- a/lib/routes/custom_appBar.dart +++ b/lib/routes/custom_appBar.dart @@ -295,7 +295,7 @@ class _CustomAppBarState extends State { layoutColor!, // () => context.go('/listPlan'), isSelected: selectedTab == TabSelection.myTrips, - icon: Icons.request_page_outlined, + icon: Icons.shopping_bag_outlined, ), // if (userDetails["role"] == "Travel Agent") // buildNavItem("My Trips", _myTravelRequestColor, @@ -319,7 +319,7 @@ class _CustomAppBarState extends State { layoutColor!, // () => context.go('/ApprovalList'), isSelected: selectedTab == TabSelection.myApprovals, - icon: Icons.assessment_outlined, + icon: Icons.verified_outlined, ), // buildNavItem("My Approvals", _myApprovalsColor, () {