nhance_partner/lib/presentation/screens/UserManagement/SalesExecutive/salesExecutiveList.dart
2026-01-08 16:01:06 +05:30

499 lines
17 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<SalesExecutiveList> createState() => SalesExecutiveListState();
}
class SalesExecutiveListState extends ConsumerState<SalesExecutiveList> {
int currentPage = 1;
int itemsPerPage = 10;
late ApiService apiService;
dynamic managerId;
dynamic role;
dynamic prefid;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getStaffData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> 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<dynamic> 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<void> 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<Map<String, dynamic>>.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<void> 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<String, dynamic> 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.70.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),
);
}