nhance_partner/lib/presentation/screens/UserManagement/Agent/agentList.dart
2026-04-08 15:55:08 +05:30

997 lines
36 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:file_picker/file_picker.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../../../core/routing/routes.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/utils/Pagination.dart';
import '../../../../data/utils/toastNotification.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';
import 'agentIncentiveFile.dart';
class AgentList extends ConsumerStatefulWidget {
const AgentList({super.key});
@override
ConsumerState<AgentList> createState() => AgentListState();
}
class AgentListState extends ConsumerState<AgentList> {
int currentPage = 1;
int itemsPerPage = 10;
late ApiService apiService;
dynamic managerId;
dynamic selected_id;
// List<Map<String, dynamic>> dataVal = [];
List<Map<String, dynamic>> getAgentData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
bool isLoading = false;
bool isRetentionImportLoading = false;
dynamic sortedData;
dynamic managerID;
@override
void initState() {
super.initState();
apiService = ApiService();
// getAgentList();
Future.microtask(() {
managerID = ref.read(managerIdProvider);
if (managerID != null) {
getAgentList(managerID);
}
});
}
void refresh() {
if (managerID != null) {
getAgentList(managerID);
}
}
// @override
// void didChangeDependencies() {
// super.didChangeDependencies();
// final id = ref.watch(managerIdProvider);
// if (id != null) {
// getAgentList(id);
// }
// }
// List<dynamic> get _paginatedData {
// final startIndex = (currentPage - 1) * itemsPerPage;
// final endIndex = (currentPage * itemsPerPage).clamp(0, filteredData.length);
// return filteredData.sublist(startIndex, endIndex);
// }
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(() {
filteredData = getAgentData.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['agent_code'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['sales_executive_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(isActiveStatus.contains(query.toLowerCase()));
}).toList();
});
}
final TextEditingController _searchController = TextEditingController();
Future<void> getAgentList(int managerId) async {
print('getClaimList called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchAgentUserList(managerId);
if (response['status'] == 'success') {
print('getAgentListData - ${response['data']}');
setState(() {
getAgentData = List<Map<String, dynamic>>.from(response['data']);
// print('API Data - $getClaimPolicies');
//
originalData = getAgentData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
});
} else {
// getClaimPolicies = [];
// originalData = getClaimPolicies;
// filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
// print('Request failed: ${response['code']}');
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> _exportRetentionRateExcel() async {
/****** Export confirmation dialog kept for future use ********/
// final proceed = await showDialog<bool>(
// context: context,
// builder: (ctx) {
// return AlertDialog(
// title: const Text('Export Rentation Rate'),
// content: const Text(
// 'The downloaded Excel will include input validation.\n\n'
// 'Allowed values: only numbers from 0 to 100.\n'
// 'Not allowed: negative values, values above 100, text/special characters.',
// ),
// actions: [
// TextButton(
// onPressed: () => Navigator.pop(ctx, false),
// child: const Text('Cancel'),
// ),
// ElevatedButton(
// onPressed: () => Navigator.pop(ctx, true),
// child: const Text('Download'),
// ),
// ],
// );
// },
// );
// if (proceed != true) return;
/****** *************************************************** ********/
try {
await apiService.downloadAgentRetentionRateExcel();
if (mounted) {
ToastHelper.showSuccessToast(
context,
'Retention rate Excel downloaded',
);
}
} catch (e) {
if (mounted) {
ToastHelper.showErrorToast(
context,
'Failed to export retention rate Excel',
);
}
}
}
Future<void> _importRetentionRateExcel() async {
final picked = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: const ['xls', 'xlsx'],
withData: true,
);
if (picked == null || picked.files.isEmpty) {
return;
}
final file = picked.files.first;
if (file.bytes == null) {
if (mounted) {
ToastHelper.showErrorToast(context, 'Could not read selected file');
}
return;
}
setState(() {
isRetentionImportLoading = true;
});
try {
final response = await apiService.importAgentRetentionRateExcel(file: file);
final status = (response['status'] ?? '').toString().toLowerCase();
if (status == 'success') {
final data = (response['data'] is Map<String, dynamic>)
? response['data'] as Map<String, dynamic>
: <String, dynamic>{};
final report = (response['report'] is Map<String, dynamic>)
? response['report'] as Map<String, dynamic>
: <String, dynamic>{};
final inserted = (data['inserted_cells'] ?? data['inserted_rows'] ?? 0);
final updated = (data['updated_cells'] ?? data['updated_rows'] ?? 0);
final message = (response['message'] ?? '').toString().trim();
if (mounted) {
ToastHelper.showSuccessToast(
context,
message.isNotEmpty
? message
: 'Import done',
// 'Import done (Inserted: $inserted, Updated: $updated)',
);
}
// if (report.isNotEmpty && mounted) {
// await _showRetentionImportReportDialog(data, report);
// }
refresh();
} else {
if (mounted) {
final message = (response['message'] ?? 'Import failed').toString();
ToastHelper.showErrorToast(context, message);
}
}
} catch (e) {
if (mounted) {
ToastHelper.showErrorToast(context, 'Failed to import retention rate');
}
} finally {
if (mounted) {
setState(() {
isRetentionImportLoading = false;
});
}
}
}
Future<void> _showRetentionImportReportDialog(
Map<String, dynamic> data,
Map<String, dynamic> report,
) async {
if (!mounted) return;
final inserted = data['inserted_cells'] ?? 0;
final updated = data['updated_cells'] ?? 0;
final skippedZero = data['skipped_zero'] ?? 0;
final skippedSame = data['skipped_same'] ?? 0;
final skippedEmptyRow = data['skipped_empty_row'] ?? 0;
final skippedEmptyCell = data['skipped_empty_cell'] ?? 0;
final skippedUnknownAgent = data['skipped_unknown_agent'] ?? 0;
final invalidRange = data['invalid_range'] ?? 0;
final invalidNumber = data['invalid_number'] ?? 0;
final unknownAgents = (report['unknown_agent_codes'] as List?)
?.map((e) => e.toString())
.where((e) => e.trim().isNotEmpty)
.toList() ??
<String>[];
final unknownVehicleTypes = ((report['unknown_vehicle_types'] ??
report['unknown_vehicle_type_names']) as List?)
?.map((e) => e.toString())
.where((e) => e.trim().isNotEmpty)
.toList() ??
<String>[];
final unknownSegments = ((report['unknown_segments'] ??
report['unknown_segment_names']) as List?)
?.map((e) => e.toString())
.where((e) => e.trim().isNotEmpty)
.toList() ??
<String>[];
final invalidCells = (report['invalid_cells'] as List?)
?.map((e) => e.toString())
.where((e) => e.trim().isNotEmpty)
.toList() ??
<String>[];
final agentWiseSkippedRaw = (report['agent_wise_skipped_counts'] is Map)
? Map<String, dynamic>.from(report['agent_wise_skipped_counts'] as Map)
: <String, dynamic>{};
final lines = <String>[
'Inserted: $inserted',
'Updated: $updated',
// 'Skipped (value = 0): $skippedZero',
// 'Skipped (Excel value equals DB value): $skippedSame',
// 'Skipped (empty first column / agent code): $skippedEmptyRow',
// 'Skipped (empty cell): $skippedEmptyCell',
// 'Skipped (unknown agent code): $skippedUnknownAgent',
'Skipped (out of range 0-100): $invalidRange',
'Skipped (non-numeric value): $invalidNumber',
];
if (unknownAgents.isNotEmpty) {
lines.add('');
lines.add('Unknown Agent Codes:');
lines.addAll(unknownAgents.take(10).map((e) => '- $e'));
if (unknownAgents.length > 10) {
lines.add('- ...and ${unknownAgents.length - 10} more');
}
}
if (unknownVehicleTypes.isNotEmpty) {
lines.add('');
lines.add('Unknown Vehicle Types:');
lines.addAll(unknownVehicleTypes.take(10).map((e) => '- $e'));
if (unknownVehicleTypes.length > 10) {
lines.add('- ...and ${unknownVehicleTypes.length - 10} more');
}
}
if (unknownSegments.isNotEmpty) {
lines.add('');
lines.add('Unknown Segments:');
lines.addAll(unknownSegments.take(10).map((e) => '- $e'));
if (unknownSegments.length > 10) {
lines.add('- ...and ${unknownSegments.length - 10} more');
}
}
if (invalidCells.isNotEmpty) {
lines.add('');
lines.add('Invalid Cell Samples:');
lines.addAll(invalidCells.take(10).map((e) => '- $e'));
if (invalidCells.length > 10) {
lines.add('- ...and ${invalidCells.length - 10} more');
}
}
if (agentWiseSkippedRaw.isNotEmpty) {
final sorted = agentWiseSkippedRaw.entries.toList()
..sort((a, b) {
final av = int.tryParse(a.value.toString()) ?? 0;
final bv = int.tryParse(b.value.toString()) ?? 0;
return bv.compareTo(av);
});
final nonZero = sorted
.where((e) => (int.tryParse(e.value.toString()) ?? 0) > 0)
.toList();
if (nonZero.isNotEmpty) {
lines.add('');
lines.add('Skipped Count (Agent Wise):');
lines.addAll(
nonZero
.take(20)
.map((e) => '- ${e.key}: ${int.tryParse(e.value.toString()) ?? 0}'),
);
if (nonZero.length > 20) {
lines.add('- ...and ${nonZero.length - 20} more');
}
}
}
await showDialog<void>(
context: context,
builder: (ctx) {
return AlertDialog(
title: const Text('Retention Rate Import Report'),
content: SizedBox(
width: 520,
child: SingleChildScrollView(
child: SelectableText(lines.join('\n')),
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('OK'),
),
],
);
},
);
}
List<Widget> _buildPopupMenuActions(BuildContext context, dynamic data) {
return [
GestureDetector(
onTap: () {
Navigator.pop(context);
print('EDIT - ${data['id']}');
dynamic id = data['id'];
context.go(AppRoutes.agentDetailsFor(id.toString()));
},
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: "Partner",
body: SelectionArea(
child: Container(
// color: Colors.yellow.shade50,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
// Container(
// // height: 30,
// // color: Colors.red.shade50,
// width: MediaQuery.of(context).size.width,
// child: GestureDetector(
// onTap: () {
// context.go(AppRoutes.dashboard);
// },
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// // Tooltip(
// // message: 'Back',
// // child: IconButton(
// // icon: const Icon(
// // Icons.arrow_left_sharp,
// // size: 25,
// // color: Color(0xFF425B5B),
// // ),
// // onPressed: () {
// // context.go(AppRoutes.dashboard);
// // },
// // splashRadius: 18,
// // hoverColor: Colors.black12,
// // padding: const EdgeInsets.all(4),
// // constraints: const BoxConstraints(),
// // ),
// // ),
// // const SizedBox(width: 5), // spacing between icon and text
// Text(
// "Partner",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w500,
// ),
// ),
// ],
// ),
// ),
// ),
// SizedBox(height: 5),
Expanded(
child: Container(
// color: Colors.green,
// color: Colors.green.shade50,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Container(
// height: 40,
// color: Colors.pink,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Partner",
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
Spacer(),
ThemedSearchField(
hintText: 'Search',
backgroundColor: Color(0xFFFFFFFF),
// backgroundColor: Color(0xFFF6F8F8),
txtHeight: 30,
onChanged: filterData,
controller: _searchController,
txtwidth: MediaQuery.of(context).size.width * 0.15,
),
SizedBox(width: 10),
InkWell(
onTap: _exportRetentionRateExcel,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
decoration: BoxDecoration(
color: const Color(0xFF2E7D6E),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
children: [
Icon(
Icons.file_download_outlined,
color: Colors.white,
size: 16,
),
SizedBox(width: 6),
Text(
'Export Rentation Rate',
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
SizedBox(width: 10),
InkWell(
onTap: isRetentionImportLoading
? null
: _importRetentionRateExcel,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
decoration: BoxDecoration(
color: const Color(0xFF2E7D6E),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
children: [
isRetentionImportLoading
? SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: Icon(
Icons.file_upload_outlined,
color: Colors.white,
size: 16,
),
SizedBox(width: 6),
Text(
'Import Rentation Rate',
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
SizedBox(width: 10),
InkWell(
onTap: () {
showUploadIncentiveModal(context);
},
child: Container(
padding: EdgeInsets.all(5.4),
decoration: BoxDecoration(
color: const Color(0xFF2E7D6E),
// color: Color(0xFF425B5B),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
// mainAxisSize: MainAxisSize.min,
children: [
// Text(
// 'Incentive File',
// style: TextStyle(
// color: Colors.white,
// fontWeight: FontWeight.w600,
// fontSize: 12,
// ),
// ),
// SizedBox(width: 10),
Tooltip(
message: 'Incentive File',
child: Icon(
Icons.file_open_outlined,
color: Colors.white,
size: 18,
),
),
],
),
),
),
SizedBox(width: 10),
ExportBtn(
sheetName: "Partner",
fileName: "partner_list",
txt: !ResponsiveLayout.isMobile(context)
? true
: false,
data: filteredData,
displayHeaders: [
'S.No.',
'Partner Id',
'Partner Name',
'Email',
'Sales Executive Name',
'Phone Number',
'Address',
'Status',
],
keys: [
"sno", // handled internally as i + 1
"agent_code",
"name",
"email",
"sales_executive_name",
"mobile",
"address",
"is_active",
],
),
SizedBox(width: 10),
InkWell(
onTap: () {
context.go(AppRoutes.agentDetailsFor('new'));
},
child: Container(
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
// color: Color(0xFF425B5B),
color: const Color(0xFF2E7D6E),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// Text(
// 'Create New Partner',
// style: TextStyle(
// color: Colors.white,
// fontWeight: FontWeight.w600,
// fontSize: 12,
// ),
// ),
// SizedBox(width: 10),
Tooltip(
message: 'Create New Partner',
child: Icon(
Icons.add,
color: Colors.white,
size: 18,
),
),
],
),
),
),
],
),
),
SizedBox(height: 10),
Container(
// height: 50,
decoration: BoxDecoration(
color: Color(0xFFF1F5F9),
// color: Color(0xFFEDF6F5),
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 16,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
flex: 1,
child: Text('S.No.', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Partner Id', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Partner Name', style: _headerStyle),
),
Expanded(
flex: 3,
child: Text('Email', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Phone Number', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Sales Executive Name', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Address', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Status', style: _headerStyle),
),
Expanded(
flex: 1,
child: Text('Action', style: _headerStyle),
),
],
),
),
Expanded(
child: Container(
color: Colors.white,
child: _buildClaimsDataTable(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 _buildClaimsDataTable(BuildContext context) {
if (filteredData.isEmpty) {
return const SizedBox(
height: 50,
child: Center(child: Text('No available data')),
);
}
// final sortedData = [..._paginatedData]
// ..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
final sortedData = [..._paginatedData];
// final sortedData = [...filteredData]
// ..sort((a, b) => int.parse(b['id']) - int.parse(a['id']));
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 const SizedBox.shrink(); // empty widget instead of commenting
}
Widget _buildDataRow(Map<String, dynamic> item, sno) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 16),
// margin: const EdgeInsets.only(top: 10),
decoration: BoxDecoration(
color: Colors.white,
// color: Color(0xFFE0F7F9),
border: const Border(
bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1),
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)),
Expanded(flex: 1, child: Text(item['agent_code'] ?? '-', 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: 2,
child: Text(item['sales_executive_name'] ?? '-', style: _dataBold),
),
Expanded(
flex: 2,
child: Text(
item['address'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 1,
child: Row(
children: [
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",
'agent',
);
print("Response - $response");
},
// activeColor: Color(0xFF425B5B),
// activeTrackColor: Color(0xFFB2D8D3),
activeColor: Color(0xFF2E7D6E), // thumb when active
activeTrackColor: Color(0xFFDCFCE7), // 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']}');
selected_id = item['id'];
context.go(AppRoutes.agentDetailsFor(selected_id.toString()));
},
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 = TextStyle(
fontSize: 10,
fontWeight: FontWeight.w300,
color: Color(0xFF585757),
);
static final _headerStyle = GoogleFonts.poppins(
fontSize: 11.2,
fontWeight: FontWeight.w500,
color: Color(0xFF1E293B),
);
}