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

611 lines
21 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/Staff/staff.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 StaffList extends ConsumerStatefulWidget {
const StaffList({super.key});
@override
ConsumerState<StaffList> createState() => StaffListState();
}
class StaffListState extends ConsumerState<StaffList> {
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");
print("roleSTAFFLIST: $role");
if (prefid != null && role != null) {
getStaffList(prefid, role);
}
});
// getStaffList();
}
void refresh() {
if (prefid != null && role != null) {
getStaffList(prefid, role);
}
}
//
// @override
// void didChangeDependencies() {
// super.didChangeDependencies();
// final id = ref.watch(managerIdProvider);
// if (id != null) {
// getStaffList(id);
// }
// }
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) {
// print("FilterDAta - $query");
// setState(() {
// filteredData = getStaffData.where((item) {
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
//
// return (item['name'] ?? '-').toLowerCase().contains(
// query.toLowerCase(),
// ) ||
// (item['email'] ?? '-').toLowerCase().contains(
// query.toLowerCase(),
// ) ||
// (item['mobile'] ?? '-').toLowerCase().contains(
// query.toLowerCase(),
// ) ||
// (item['address'] ?? '-').toLowerCase().contains(
// query.toLowerCase(),
// ) ||
// (item['emp_id'] ?? item['agent_code'] ?? '-')
// .toLowerCase()
// .contains(query.toLowerCase()) ||
// isActiveStatus.contains(query.toLowerCase());
// }).toList();
// });
// }
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['role'] ?? '').toString().toLowerCase().contains(q) ||
(item['emp_id'] ?? item['agent_code'] ?? '')
.toString()
.toLowerCase()
.contains(q) ||
isActiveStatus.contains(q);
}).toList();
});
}
final TextEditingController _searchStaffController = TextEditingController();
Future<void> getStaffList(int id, role) async {
print('E104 => Fns called => $id');
print('E104 => Fns role => $role');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchStaffUserList(id, role);
if (response['status'] == 'success') {
print('E113 => getStaffListData => ${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> showStaff({required String id}) {
print('showAgent : $id');
return showDialog(
context: context,
builder: (ctx) => Staff(
id: id,
onSubmit: (value) {
debugPrint("New Claims: $value");
refresh();
},
),
);
}
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
return [
GestureDetector(
onTap: () {
Navigator.pop(context);
print('EDITStaff - ${data['id']}');
dynamic id = data['id'];
context.go('/staff/$id');
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18),
SizedBox(width: 10),
Text('Edit'),
],
),
),
];
}
@override
Widget build(BuildContext context) {
managerId = ref.watch(managerIdProvider);
return MainLayout(
title: "Staff",
body: SelectionArea(
child: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(
'Staff',
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: "Staff",
fileName: "staff_list",
txt: !ResponsiveLayout.isMobile(context)
? true
: false,
data: filteredData,
displayHeaders: [
'S.No.',
'Staff Name',
'Role',
'Email',
'Phone Number',
'Status',
],
keys: [
"sno", // handled internally as i + 1
"name",
"role",
"email",
"mobile",
"is_active",
],
),
SizedBox(width: 10),
InkWell(
onTap: () {
// context.go('/staff/create');
showStaff(id: '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 Staff',
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('Staff Name', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Role', 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: 1, child: Text(item['role'] ?? '-', 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",
'staff',
);
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: [
// GestureDetector(
// onTap: () {
// // Navigator.pop(context);
// print('EDITStaff - ${item['id']}');
// dynamic id = item['id'];
// context.go('/staff/$id');
// },
// child: Image.asset(
// "assets/miscellaneous/Edit.png",
// height: 15,
// width: 15,
// ),
// ),
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'];
showStaff(id: id);
// context.go('/staff/$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,
),
],
),
),
// Expanded(
// flex: 1,
// child: Row(
// children: [
// PopupMenuButton<int>(
// color: Colors.white,
// padding: EdgeInsets.zero,
// offset: Offset(0, 30),
// icon: Icon(
// Icons.more_vert,
// color: Color(0xFF475569),
// size: 14,
// ),
// itemBuilder: (context) => [
// if (item['is_active'] == "1")
// CustomPopupMenuEntry(
// child: Container(
// padding: EdgeInsets.symmetric(
// horizontal: 8,
// vertical: 8,
// ),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.center,
// children: _buildPopupMenuActions(context, item),
// ),
// ),
// ),
// ],
// ),
// ],
// ),
// ),
],
),
);
}
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),
);
}