import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; import 'package:nhance_partner/presentation/screens/UserManagement/SalesExecutive/salesExecutive.dart'; import '../../../../core/routing/routes.dart'; import '../../../../core/services/api_service.dart'; import '../../../../data/utils/Pagination.dart'; import '../../../layouts/main_layout.dart'; import '../../../layouts/responsive_layout.dart'; import '../../../providers/manager_provider.dart'; import '../../../themes/indicators/export_btn.dart'; import '../../../themes/indicators/filter_btn.dart'; import '../../../themes/indicators/search_field_theme.dart'; import '../../../themes/indicators/text_field_theme.dart'; import '../../../widgets/custom_action_popup.dart'; class SalesExecutiveList extends ConsumerStatefulWidget { const SalesExecutiveList({super.key}); @override ConsumerState createState() => SalesExecutiveListState(); } class SalesExecutiveListState extends ConsumerState { int currentPage = 1; int itemsPerPage = 10; late ApiService apiService; dynamic managerId; dynamic role; dynamic prefid; // List> dataVal = []; List> getStaffData = []; List> originalData = []; List> filteredData = []; bool isLoading = false; @override void initState() { super.initState(); apiService = ApiService(); Future.microtask(() { final data1 = ref.read(managerIdProvider); // final data2 = ref.read(handlerIdProvider); print("Edata1 => mId: $data1 -2 :"); prefid = data1; role = ref.read(userRoleProvider); print("E43 => mId: $prefid"); if (prefid != null && role != null) { getSalesExecutiveList(prefid, role); } }); // getSalesExecutiveList(); } void refresh() { if (prefid != null && role != null) { getSalesExecutiveList(prefid, role); } } List get _paginatedData { // Sort descending by id first final sortedData = [...filteredData] ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); if (sortedData.isEmpty) return []; // Ensure currentPage is valid final maxPage = (sortedData.length / itemsPerPage).ceil(); final safePage = currentPage.clamp(1, maxPage); final startIndex = (safePage - 1) * itemsPerPage; final endIndex = (startIndex + itemsPerPage).clamp(0, sortedData.length); return sortedData.sublist(startIndex, endIndex); } void filterData(String query) { setState(() { final q = query.toLowerCase(); if (q.isEmpty) { filteredData = getStaffData; return; } filteredData = getStaffData.where((item) { final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive"; return (item['name'] ?? '').toString().toLowerCase().contains(q) || (item['email'] ?? '').toString().toLowerCase().contains(q) || (item['mobile'] ?? '').toString().toLowerCase().contains(q) || (item['address'] ?? '').toString().toLowerCase().contains(q) || (item['emp_id'] ?? item['agent_code'] ?? '') .toString() .toLowerCase() .contains(q) || isActiveStatus.contains(q); }).toList(); }); } final TextEditingController _searchStaffController = TextEditingController(); Future getSalesExecutiveList(int id, role) async { print('E104 => Fns called => $id'); print('E104 => Fns role => $role'); setState(() { isLoading = true; }); try { final response = await apiService.fetchSalesExecutiveList(id, role); if (response['status'] == 'success') { print('E113 => getSalesExecutiveListData => ${response['data']}'); setState(() { getStaffData = List>.from(response['data']); originalData = getStaffData; filteredData = List.from(originalData); // print('originalData - $getClaimPolicies'); }); } else { getStaffData = []; originalData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } Future showSalesExecutive({required String id}) { print('showSalesEXEC : $id'); return showDialog( context: context, builder: (ctx) => SalesExecutive( id: id, onSubmit: (value) { debugPrint("New onSubmit: $value"); refresh(); }, ), ); } @override Widget build(BuildContext context) { managerId = ref.watch(managerIdProvider); return SelectionArea( child:MainLayout( title: "Sales Executive", body: Container( // padding: EdgeInsets.all(8.0), // margin: EdgeInsets.all(10.0), // color: Colors.yellow.shade50, width: MediaQuery.of(context).size.width, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( child: Container( // color: Colors.green, // color: Colors.green.shade50, width: MediaQuery.of(context).size.width, // margin: EdgeInsets.all(10.0), decoration: BoxDecoration( // color: Colors.white, borderRadius: BorderRadius.circular(15.0), ), padding: EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( // height: 40, // color: Colors.pink, child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( 'Sales Executive', style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.w500, ), ), Spacer(), ThemedSearchField( hintText: 'Search', // backgroundColor: Color(0xFFF6F8F8), backgroundColor: Color(0xFFFFFFFF), txtHeight: 30, onChanged: filterData, controller: _searchStaffController, txtwidth: MediaQuery.of(context).size.width * 0.15, ), SizedBox(width: 10), ExportBtn( sheetName: "SalesExecutive", fileName: "salesExecutive_list", txt: !ResponsiveLayout.isMobile(context) ? true : false, data: filteredData, displayHeaders: [ 'S.No.', 'Staff Name', 'Email', 'Phone Number', 'Address', 'Status', ], keys: [ "sno", // handled internally as i + 1 "name", "email", "mobile", "address", "is_active", ], ), SizedBox(width: 10), InkWell( onTap: () { showSalesExecutive(id: 'create'); // context.go('/salesExecutive/create'); }, child: Container( padding: EdgeInsets.all(4.8), decoration: BoxDecoration( color: const Color(0xFF2E7D6E), borderRadius: BorderRadius.circular(8.0), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Tooltip( message: 'Create Sales Executive', child: Icon( Icons.add, color: Colors.white, size: 18, ), ), ], ), ), ), ], ), ), SizedBox(height: 5), Container( decoration: BoxDecoration( color: Color(0xFFF1F5F9), // color: Color(0xFFEDF6F5), borderRadius: BorderRadius.circular(6), ), padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 16, ), child: Row( children: [ Expanded( flex: 1, child: Text('S.No.', style: _headerStyle), ), Expanded( flex: 2, child: Text('Executive Name', style: _headerStyle), ), Expanded( flex: 3, child: Text('Email', style: _headerStyle), ), Expanded( flex: 2, child: Text('Phone Number', style: _headerStyle), ), Expanded( flex: 1, child: Text('Status', style: _headerStyle), ), Expanded( flex: 1, child: Text('Action', style: _headerStyle), ), ], ), ), Expanded(child: _buildDataTable(context)), ], ), ), ), Container( // height: 20, width: MediaQuery.of(context).size.width, // color: Colors.green.shade50, child: PaginationControls( currentPage: currentPage, itemsPerPage: itemsPerPage, // totalItems: dataVal.length, totalItems: filteredData.length, // activeColor: layoutColor, // your theme color onPageChanged: (page) { setState(() { currentPage = page; }); }, onItemsPerPageChanged: (items) { setState(() { itemsPerPage = items; currentPage = 1; }); }, ), ), ], ), ), ),); } Widget _buildDataTable(BuildContext context) { if (filteredData.isEmpty) { return const SizedBox( height: 50, child: Center(child: Text('No available data')), ); } final sortedData = [..._paginatedData]; return ListView.builder( // itemCount: filteredData.length + 1, // +1 for header, +1 for pagination itemCount: sortedData.length + 1, // +1 for header, +1 for pagination itemBuilder: (context, index) { if (index == 0) return _buildHeader(); // if (index == dataVal.length + 1) // return _buildPagination(context); final startIndex = ((currentPage - 1) * itemsPerPage); // final item = filteredData[index - 1]; final item = sortedData[index - 1]; final sno = startIndex + index; return _buildDataRow(item, sno); }, ); } Widget _buildHeader() { return SizedBox.shrink(); } Widget _buildDataRow(Map item, sno) { return Container( padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 16), // margin: const EdgeInsets.only(top: 10), decoration: BoxDecoration( color: Colors.white, // color: Color(0xFFE0F7F9), border: const Border( bottom: BorderSide(color: Colors.blueGrey, width: 0.15), ), // borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)), Expanded(flex: 2, child: Text(item['name'] ?? '-', style: _dataBold)), Expanded( flex: 3, child: Text(item['email'] ?? '-', style: _dataBold), ), Expanded( flex: 2, child: Text(item['mobile'] ?? '-', style: _dataBold), ), Expanded( flex: 1, child: Row( children: [ Container( // color: Colors.yellow.shade50, child: Transform.scale( scale: 0.4, // reduce size (0.7–0.9 works well) child: Switch( value: item['is_active'] == "1", onChanged: (val) { setState(() { item['is_active'] = val ? "1" : "0"; }); final response = apiService.updateStatus( item['id'], val ? "0" : "1", 'salesExecutive', ); print("Response - $response"); }, activeColor: Color(0xFF2E7D6E), // thumb when active activeTrackColor: Color(0xFFDCFCE7), // track when active // activeColor: Color(0xFF425B5B), // thumb when active // activeTrackColor: Color(0xFFB2D8D3), // track when active inactiveThumbColor: Colors.grey.shade400, // thumb when inactive inactiveTrackColor: Colors.grey.shade300, // track when inactive ), ), ), ], ), ), Expanded( flex: 1, child: item['is_active'] == "1" ? Row( children: [ Tooltip( message: 'Edit', child: IconButton( icon: Image.asset( "assets/miscellaneous/Edit.png", height: 12, width: 15, ), onPressed: () { print('EDITStaff - ${item['id']}'); dynamic id = item['id']; // context.go('/salesExecutive/$id'); showSalesExecutive(id: id); }, splashRadius: 28, hoverColor: Colors.black12, padding: const EdgeInsets.all(8), constraints: const BoxConstraints(), ), ), ], ) : Row( children: [ Image.asset( "assets/miscellaneous/Edit_muted.png", height: 12, width: 15, ), ], ), ), ], ), ); } static final _dataBold = GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w400, color: Color(0xFF000000), ); static final _dataSub = GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.w300, color: Color(0xFF585757), ); static final _headerStyle = GoogleFonts.poppins( fontSize: 11.2, fontWeight: FontWeight.w500, color: Color(0xFF1E293B), ); }