Export_header

This commit is contained in:
venbaittech 2025-10-27 13:11:22 +05:30
parent 6c1fdb1c10
commit 626b09e3c9
13 changed files with 488 additions and 315 deletions

View File

@ -571,15 +571,35 @@ class EnquiryListState extends ConsumerState<EnquiryList> {
fileName: "enquiry_list", fileName: "enquiry_list",
data: filteredData, data: filteredData,
txt: !ResponsiveLayout.isMobile(context) ? true : false, txt: !ResponsiveLayout.isMobile(context) ? true : false,
headers: [
"id", // headers: [],
displayHeaders: [
"S.No.",
"Received Date & Time",
"Vehicle.No.",
"Insurer",
"Updated Date",
"Status",
"Remarks",
],
keys: [
"sno", // handled internally as i + 1
"created_on", "created_on",
"updated_on",
"reg_no", "reg_no",
"insurer_name", "insurer_name",
"updated_on",
"status", "status",
"remarks", "remarks",
], ],
// headers: [
// "id",
// "created_on",
// "updated_on",
// "reg_no",
// "insurer_name",
// "status",
// "remarks",
// ],
), ),
SizedBox(width: 10), SizedBox(width: 10),

View File

@ -255,7 +255,18 @@ class claimListState extends ConsumerState<claimList> {
txt: !ResponsiveLayout.isMobile(context) txt: !ResponsiveLayout.isMobile(context)
? true ? true
: false, : false,
headers: [ displayHeaders: [
"S.No.",
"Vehicle.No.",
"Insurer",
"Policy No.",
"Policy Expiry Date",
"Claim Type",
"Claim No.",
"Status",
],
keys: [
"sno", // handled internally as i + 1
"reg_no", "reg_no",
"insurer_name", "insurer_name",
"policy_no", "policy_no",

View File

@ -252,7 +252,16 @@ class endosementState extends ConsumerState<endosement> {
txt: !ResponsiveLayout.isMobile(context) txt: !ResponsiveLayout.isMobile(context)
? true ? true
: false, : false,
headers: [ displayHeaders: [
"S.No.",
"Vehicle.No.",
"Insurer",
"Policy No.",
"Endorsement Type",
"Endorsement No.",
],
keys: [
"sno", // handled internally as i + 1
"reg_no", "reg_no",
"insurer_name", "insurer_name",
"policy_number", "policy_number",

View File

@ -409,7 +409,12 @@ class AttendanceAllDetailsState extends ConsumerState<AttendanceAllDetails> {
fileName: "staff_attendance_list", fileName: "staff_attendance_list",
data: filteredData, data: filteredData,
txt: !ResponsiveLayout.isMobile(context) ? true : false, txt: !ResponsiveLayout.isMobile(context) ? true : false,
headers: ["staff_id", "staff_name", "month", "login_count"],
displayHeaders: ["S.No.", "Staff Name", "Month", "Days"],
keys: [
"sno", // handled internally as i + 1
"staff_name", "month", "login_count",
],
), ),
], ],
), ),

View File

@ -253,6 +253,7 @@ class IndividualAttendanceDetailsState
return (item['date'] ?? '-').toLowerCase().contains( return (item['date'] ?? '-').toLowerCase().contains(
query.toLowerCase(), query.toLowerCase(),
) || ) ||
(item['name'] ?? '-').toLowerCase().contains(query.toLowerCase()) ||
(item['login_time'] ?? '-').toLowerCase().contains( (item['login_time'] ?? '-').toLowerCase().contains(
query.toLowerCase(), query.toLowerCase(),
) || ) ||
@ -321,7 +322,7 @@ class IndividualAttendanceDetailsState
), ),
const SizedBox(width: 5), // spacing between icon and text const SizedBox(width: 5), // spacing between icon and text
Text( Text(
"Attendance For $staffName", "Attendance",
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18, fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -416,8 +417,17 @@ class IndividualAttendanceDetailsState
fileName: "staff_individual_attendance_list", fileName: "staff_individual_attendance_list",
data: filteredData, data: filteredData,
txt: !ResponsiveLayout.isMobile(context) ? true : false, txt: !ResponsiveLayout.isMobile(context) ? true : false,
headers: [ displayHeaders: [
"id", "S.No.",
"Name",
"Date",
"Login",
"Logout",
"Number Of Hours",
],
keys: [
"sno", // handled internally as i + 1
"name",
"date", "date",
"login_time", "login_time",
"logout_time", "logout_time",
@ -438,6 +448,7 @@ class IndividualAttendanceDetailsState
child: Row( child: Row(
children: [ children: [
Expanded(flex: 1, child: Text('S.No.', style: _headerStyle)), Expanded(flex: 1, child: Text('S.No.', style: _headerStyle)),
Expanded(flex: 2, child: Text('Name', style: _headerStyle)),
Expanded(flex: 2, child: Text('Date', style: _headerStyle)), Expanded(flex: 2, child: Text('Date', style: _headerStyle)),
Expanded(flex: 2, child: Text('Login', style: _headerStyle)), Expanded(flex: 2, child: Text('Login', style: _headerStyle)),
@ -502,6 +513,7 @@ class IndividualAttendanceDetailsState
child: Row( child: Row(
children: [ children: [
Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)), Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)),
Expanded(flex: 2, child: Text(item['name'] ?? '-', style: _dataBold)),
Expanded(flex: 2, child: Text(item['date'] ?? '-', style: _dataBold)), Expanded(flex: 2, child: Text(item['date'] ?? '-', style: _dataBold)),
Expanded( Expanded(

View File

@ -528,6 +528,9 @@ class AgentState extends ConsumerState<Agent> {
SizedBox(width: 10), SizedBox(width: 10),
ThemedFormField( ThemedFormField(
controller: controllers['code']!, controller: controllers['code']!,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9]')),
],
validator: (value) => Validators.requiredField(value, "id"), validator: (value) => Validators.requiredField(value, "id"),
txtwidth: MediaQuery.of(context).size.width * 0.26, txtwidth: MediaQuery.of(context).size.width * 0.26,
), ),

View File

@ -280,12 +280,21 @@ class AgentListState extends ConsumerState<AgentList> {
? true ? true
: false, : false,
data: filteredData, data: filteredData,
headers: [ displayHeaders: [
"id", 'S.No.',
'Partner Name',
'Email',
'Phone Number',
'Id',
'Address',
'Status',
],
keys: [
"sno", // handled internally as i + 1
"name", "name",
"agent_code",
"email", "email",
"mobile", "mobile",
"agent_code",
"address", "address",
"is_active", "is_active",
], ],

View File

@ -255,12 +255,20 @@ class StaffListState extends ConsumerState<StaffList> {
? true ? true
: false, : false,
data: filteredData, data: filteredData,
headers: [ displayHeaders: [
"id", 'S.No.',
'Staff Name',
'Role',
'Email',
'Phone Number',
'Status',
],
keys: [
"sno", // handled internally as i + 1
"name", "name",
"role",
"email", "email",
"mobile", "mobile",
"role",
"is_active", "is_active",
], ],
), ),

View File

@ -1234,7 +1234,7 @@ class othersPendings extends StatelessWidget {
flex: 2, flex: 2,
child: Text( child: Text(
// stringFlag + " Issued", // stringFlag + " Issued",
'Pending Enquiries', 'Total Assigned',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: _headerStyle, style: _headerStyle,
), ),
@ -1344,69 +1344,81 @@ class othersPendings extends StatelessWidget {
), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: InkWell( child: Material(
onTap: () { color: Colors.white,
print( child: InkWell(
'Awaiting Proposal : ${row['awaiting_quotation']}', hoverColor: Color(0xFFEAF6F4),
); onTap: () {
print(
'Awaiting Proposal : ${row['awaiting_quotation']}',
);
handleDashboardNavigation( handleDashboardNavigation(
context, context,
status: "Awaiting Proposal", status: "Awaiting Proposal",
staffId: row['staff_id'] ?? '', staffId: row['staff_id'] ?? '',
role: role, role: role,
); );
}, },
child: Text( child: Text(
row['awaiting_quotation'] ?? "", row['awaiting_quotation'] ?? "",
// row['total_approval_pending'] ?? "", // row['total_approval_pending'] ?? "",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: _tableDataStyle, style: _tableDataStyle,
),
), ),
), ),
), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: InkWell( child: Material(
onTap: () async { color: Colors.white,
print( child: InkWell(
'Awaiting Approval : ${row['pending_quotation_approval']} - ${row['staff_id']}', hoverColor: Color(0xFFEAF6F4),
); onTap: () async {
handleDashboardNavigation( print(
context, 'Awaiting Approval : ${row['pending_quotation_approval']} - ${row['staff_id']}',
status: "Proposal Created", );
staffId: row['staff_id'] ?? '', handleDashboardNavigation(
role: role, context,
); status: "Proposal Created",
}, staffId: row['staff_id'] ?? '',
child: Text( role: role,
row['pending_quotation_approval'] ?? "", );
// row['total_approval_pending'] ?? "", },
textAlign: TextAlign.center, child: Text(
style: _tableDataStyle, row['pending_quotation_approval'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
), ),
), ),
), ),
Expanded( Expanded(
flex: 2, flex: 2,
child: InkWell( child: Material(
onTap: () { color: Colors.white,
print( child: InkWell(
'Awaiting Policy : ${row['awaiting_policy']}', hoverColor: Color(0xFFEAF6F4),
); onTap: () {
print(
'Awaiting Policy : ${row['awaiting_policy']}',
);
handleDashboardNavigation( handleDashboardNavigation(
context, context,
status: "Proposal Accepted", status: "Proposal Accepted",
staffId: row['staff_id'] ?? '', staffId: row['staff_id'] ?? '',
role: role, role: role,
); );
}, },
child: Text( child: Text(
row['awaiting_policy'] ?? "", row['awaiting_policy'] ?? "",
// row['total_approval_pending'] ?? "", // row['total_approval_pending'] ?? "",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: _tableDataStyle, style: _tableDataStyle,
),
), ),
), ),
), ),

View File

@ -764,14 +764,27 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
fileName: "Enquiry_list", fileName: "Enquiry_list",
data: filteredData, data: filteredData,
txt: !ResponsiveLayout.isMobile(context) ? true : false, txt: !ResponsiveLayout.isMobile(context) ? true : false,
headers: [ displayHeaders: [
"Received Date & Time",
"Partner",
"Assigned To",
"Insurer",
"Vehicle.No.",
"Insured Name",
"Assigned Date & Time",
"Premium",
"Payment Mode",
"Policy Number",
"Status",
],
keys: [
"created_on", "created_on",
"updated_on",
"reg_no",
"agent_name", "agent_name",
"assigned_to_name", "assigned_to_name",
"insurer_name", "insurer_name",
"reg_no",
"insured_name", "insured_name",
"updated_on",
"premium_amount", "premium_amount",
"payment_mode", "payment_mode",
"policy_number", "policy_number",
@ -887,26 +900,29 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
flex: 2, flex: 2,
child: Text('Received Date', style: _headerStyle), child: Text('Received Date', style: _headerStyle),
), ),
Expanded(
flex: 2,
child: Text('Assigned Date', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('Vehicle.No', style: _headerStyle),
),
Expanded(flex: 2, child: Text('Partner', style: _headerStyle)), Expanded(flex: 2, child: Text('Partner', style: _headerStyle)),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text('Assigned To', style: _headerStyle), child: Text('Assigned To', style: _headerStyle),
), ),
Expanded(flex: 3, child: Text('Insurer', style: _headerStyle)), Expanded(flex: 3, child: Text('Insurer', style: _headerStyle)),
Expanded( Expanded(
flex: 2, flex: 2,
child: Padding( child: Text('Vehicle.No', style: _headerStyle),
padding: EdgeInsets.only(left: 8.0), ),
child: Text('Insured Name', style: _headerStyle), Expanded(
), flex: 2,
// child: Padding(
// padding: EdgeInsets.only(left: 8.0),
child: Text('Insured Name', style: _headerStyle),
// ),
),
Expanded(
flex: 2,
child: Text('Assigned Date', style: _headerStyle),
), ),
Expanded(flex: 2, child: Text('Premium', style: _headerStyle)), Expanded(flex: 2, child: Text('Premium', style: _headerStyle)),
Expanded( Expanded(
@ -1023,19 +1039,7 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
maxLines: 3, maxLines: 3,
), ),
), ),
Expanded(
flex: 2,
child: Text(
_formatDate(item['updated_on']) ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(item['reg_no'] ?? '-', style: _dataBold),
),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text(item['agent_name'] ?? '-', style: _dataBold), child: Text(item['agent_name'] ?? '-', style: _dataBold),
@ -1053,6 +1057,10 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
maxLines: 3, maxLines: 3,
), ),
), ),
Expanded(
flex: 2,
child: Text(item['reg_no'] ?? '-', style: _dataBold),
),
Expanded( Expanded(
flex: 2, flex: 2,
@ -1063,6 +1071,16 @@ class EnquiryHandlerState extends ConsumerState<EnquiryHandler> {
maxLines: 3, maxLines: 3,
), ),
), ),
Expanded(
flex: 2,
child: Text(
_formatDate(item['updated_on']) ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(

View File

@ -827,17 +827,28 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
fileName: "Enquiry_list", fileName: "Enquiry_list",
data: filteredData, data: filteredData,
txt: !ResponsiveLayout.isMobile(context) ? true : false, txt: !ResponsiveLayout.isMobile(context) ? true : false,
headers: [ displayHeaders: [
"Received Date & Time",
"Partner",
"Assigned To",
"Insurer",
"Vehicle.No.",
"Insured Name",
"Assigned Date & Time",
"Status",
],
keys: [
"created_on", "created_on",
"updated_on",
"reg_no",
"agent_name", "agent_name",
"assigned_to_name", "assigned_to_name",
"insurer_name", "insurer_name",
"reg_no",
"insured_name", "insured_name",
"premium_amount", // "assigned_to_name",
"payment_mode", "updated_on",
"policy_number", // "premium_amount",
// "payment_mode",
// "policy_number",
"status", "status",
], ],
), ),
@ -859,6 +870,10 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
child: Text('Received Date & Time', style: _headerStyle), child: Text('Received Date & Time', style: _headerStyle),
), ),
Expanded(flex: 2, child: Text('Partner ', style: _headerStyle)), Expanded(flex: 2, child: Text('Partner ', style: _headerStyle)),
Expanded(
flex: 2,
child: Text('Assigned To ', style: _headerStyle),
),
Expanded(flex: 4, child: Text('Insurer', style: _headerStyle)), Expanded(flex: 4, child: Text('Insurer', style: _headerStyle)),
Expanded( Expanded(
flex: 3, flex: 3,
@ -955,6 +970,15 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
maxLines: 2, maxLines: 2,
), ),
), ),
Expanded(
flex: 2,
child: Text(
item['assigned_to_name'] ?? '-',
style: _dataBold,
softWrap: true,
maxLines: 2,
),
),
Expanded( Expanded(
flex: 4, flex: 4,
child: Text( child: Text(
@ -968,61 +992,65 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
Expanded( Expanded(
flex: 3, flex: 3,
child: Builder( child: Builder(
builder: (buttonContext) => InkWell( builder: (buttonContext) => Material(
hoverColor: const Color(0xffD9EBE8), color: Colors.white,
focusColor: const Color(0xffD9EBE8), child: InkWell(
splashColor: const Color(0xffD9EBE8), hoverColor: Color(0xFFEAF6F4),
highlightColor: const Color(0xffD9EBE8), // hoverColor: const Color(0xffD9EBE8),
onTap: () async { // focusColor: const Color(0xffD9EBE8),
// Get overlay and button position RELATIVE to InkWell // splashColor: const Color(0xffD9EBE8),
final RenderBox button = // highlightColor: const Color(0xffD9EBE8),
buttonContext.findRenderObject() as RenderBox; onTap: () async {
final RenderBox overlay = // Get overlay and button position RELATIVE to InkWell
Overlay.of(buttonContext).context.findRenderObject() final RenderBox button =
as RenderBox; buttonContext.findRenderObject() as RenderBox;
final RenderBox overlay =
Overlay.of(buttonContext).context.findRenderObject()
as RenderBox;
final Offset position = button.localToGlobal( final Offset position = button.localToGlobal(
Offset.zero, Offset.zero,
ancestor: overlay, ancestor: overlay,
); );
await showMenu( await showMenu(
context: buttonContext, context: buttonContext,
position: RelativeRect.fromLTRB( position: RelativeRect.fromLTRB(
position.dx, position.dx,
position.dy + button.size.height, position.dy + button.size.height,
overlay.size.width - position.dx, overlay.size.width - position.dx,
0, 0,
), ),
items: [ items: [
PopupMenuItem( PopupMenuItem(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: _buildPopupDownload( children: _buildPopupDownload(
buttonContext, buttonContext,
item, item,
item['id'], item['id'],
item['reg_no'], item['reg_no'],
),
), ),
), ),
), ],
], color: Colors.white,
color: Colors.white, );
); },
}, child: Tooltip(
child: Tooltip( message:
message: 'Click and Download Enquiry Files', // what appears on hover/long press
'Click and Download Enquiry Files', // what appears on hover/long press waitDuration: const Duration(milliseconds: 500), // optional
waitDuration: const Duration(milliseconds: 500), // optional showDuration: const Duration(seconds: 2), // optional
showDuration: const Duration(seconds: 2), // optional child: Text(
child: Text( item['reg_no'] ?? '-',
item['reg_no'] ?? '-', style: _dataBold,
style: _dataBold, overflow: TextOverflow
overflow: TextOverflow .ellipsis, // optional, if text might overflow
.ellipsis, // optional, if text might overflow ),
), ),
// child: Text(item['reg_no'] ?? '-', style: _dataBold),
), ),
// child: Text(item['reg_no'] ?? '-', style: _dataBold),
), ),
), ),
), ),
@ -1049,32 +1077,36 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
), ),
Expanded( Expanded(
flex: 3, flex: 3,
child: InkWell( child: Material(
onTap: () async { color: Colors.white,
var status = item['status']; child: InkWell(
var enqId = item['id']; hoverColor: Color(0xFFEAF6F4),
onTap: () async {
var status = item['status'];
var enqId = item['id'];
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
// Remove old value (if any) // Remove old value (if any)
await prefs.remove('enqStaffDataId'); await prefs.remove('enqStaffDataId');
// Save the new id // Save the new id
await prefs.setString('enqStaffDataId', enqId.toString()); await prefs.setString('enqStaffDataId', enqId.toString());
ref.read(quotationStaffIdProvider.notifier).state = enqId; ref.read(quotationStaffIdProvider.notifier).state = enqId;
buildStatusActions(context, status, enqId); buildStatusActions(context, status, enqId);
}, },
child: Tooltip( child: Tooltip(
message: 'Click to View or Process Enquiry', // message: 'Click to View or Process Enquiry', //
waitDuration: const Duration(milliseconds: 500), // optional waitDuration: const Duration(milliseconds: 500), // optional
showDuration: const Duration(seconds: 2), // optional showDuration: const Duration(seconds: 2), // optional
child: Text( child: Text(
item['status'] ?? '-', item['status'] ?? '-',
style: _dataBold, style: _dataBold,
overflow: TextOverflow.ellipsis, // overflow: TextOverflow.ellipsis, //
),
), ),
// child: Text(item['status'] ?? '-', style: _dataBold),
), ),
// child: Text(item['status'] ?? '-', style: _dataBold),
), ),
), ),
], ],

View File

@ -588,15 +588,26 @@ class policylistState extends ConsumerState<policylist> {
fileName: "Policy_list", fileName: "Policy_list",
data: filteredData, data: filteredData,
txt: !ResponsiveLayout.isMobile(context) ? true : false, txt: !ResponsiveLayout.isMobile(context) ? true : false,
headers: [ displayHeaders: [
"reg_no", "Received Date & Time",
"Partner",
"Assigned To",
"Insurer",
"Vehicle.No.",
"Insured Name",
"Premium",
"Payment Mode",
"Policy Number",
],
keys: [
"updated_on",
"agent_name", "agent_name",
"assigned_to_name", "assigned_to_name",
"insurer_name", "insurer_name",
"reg_no",
"insured_name", "insured_name",
"premium_amount", "premium_amount",
"payment_mode", "payment_mode",
"updated_on",
"policy_number", "policy_number",
], ],
), ),

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:excel/excel.dart'; import 'package:excel/excel.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:nhance_partner/data/utils/toastNotification.dart';
import 'package:open_file/open_file.dart'; import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
@ -21,91 +22,171 @@ class ExportBtn extends HookWidget {
final String sheetName; final String sheetName;
final String fileName; final String fileName;
final List<Map<String, dynamic>> data; final List<Map<String, dynamic>> data;
final List<String> headers; // dynamic headers final List<String>? displayHeaders; // dynamic headers
// final List<String> headers; // dynamic headers
final List<String>? keys; // dynamic headers
final bool? txt; final bool? txt;
const ExportBtn({ const ExportBtn({
super.key, super.key,
this.txt, this.txt,
required this.sheetName, required this.sheetName,
required this.fileName, required this.fileName,
required this.data, required this.data,
required this.headers,
// required this.headers,
required this.displayHeaders,
this.keys,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return Tooltip(
onTap: () { message: 'Export File',
ExcelExporter.exportToExcel( child: InkWell(
sheetName: sheetName, onTap: () async {
data: data, print('TAV ExcelExporter');
headers: headers, final scaffold = ScaffoldMessenger.of(context);
fileName: fileName, try {
); await ExcelExporter.exportToExcel(
}, sheetName: sheetName,
child: Container( data: data,
padding: const EdgeInsets.all(8.0), displayHeaders: displayHeaders!,
decoration: BoxDecoration( keys: keys!,
color: const Color(0xFF425B5B), fileName: fileName,
borderRadius: BorderRadius.circular(8.0), );
), ToastHelper.showSuccessToast(context, 'Export finished');
child: Row( } catch (e) {
mainAxisSize: MainAxisSize.min, ToastHelper.showErrorToast(context, 'Export failed: $e');
children: [ }
?txt! },
? Text( // onTap: () {
'Export', // print('TAV ExcelExporter');
style: TextStyle( //
color: Colors.white, // ExcelExporter.exportToExcel(
fontWeight: FontWeight.w600, // sheetName: sheetName,
fontSize: 14, // data: data,
), // headers: headers,
) // fileName: fileName,
: null, // keys: keys!,
?txt! ? SizedBox(width: 20) : null, // );
Image.asset( // },
"assets/miscellaneous/export.png", child: Container(
height: 25, padding: const EdgeInsets.all(8.0),
width: 25, decoration: BoxDecoration(
), color: const Color(0xFF425B5B),
// Icon(Icons.input_sharp, color: Colors.white), borderRadius: BorderRadius.circular(8.0),
// Image.asset("assets/miscellaneous/export", height: 15, width: 15), ),
], child: Row(
mainAxisSize: MainAxisSize.min,
children: [
?txt!
? Text(
'Export',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 14,
),
)
: null,
?txt! ? SizedBox(width: 20) : null,
Image.asset(
"assets/miscellaneous/export.png",
height: 25,
width: 25,
),
// Icon(Icons.input_sharp, color: Colors.white),
// Image.asset("assets/miscellaneous/export", height: 15, width: 15),
],
),
), ),
), ),
); );
} }
} }
class ExcelExporter { class ExcelExporter {
/// Export to an Excel file.
/// - [displayHeaders]: labels to show in Excel (e.g. "S.No.", "Status")
/// - [keys]: actual field names in your data map
static Future<void> exportToExcel({ static Future<void> exportToExcel({
required String sheetName, required String sheetName,
required List<Map<String, dynamic>> data, required List<Map<String, dynamic>> data,
required List<String> headers, required List<String> displayHeaders,
required List<String> keys,
required String fileName, required String fileName,
}) async { }) async {
try { if (displayHeaders.length != keys.length) {
// Create Excel throw ArgumentError('displayHeaders and keys must have same length');
var excel = Excel.createExcel(); }
// Rename default sheet try {
final excel = Excel.createExcel();
// Rename default sheet if needed
if (excel.sheets.containsKey('Sheet1')) { if (excel.sheets.containsKey('Sheet1')) {
excel.rename('Sheet1', sheetName); try {
excel.rename('Sheet1', sheetName);
} catch (_) {}
} }
// Get the sheet // Get the sheet
Sheet sheetObject = excel[sheetName]!; final sheet = excel[sheetName]!;
// Add headers // Add headers as CellValues
sheetObject.appendRow(headers.map((h) => TextCellValue(h)).toList()); sheet.appendRow(displayHeaders.map((h) => TextCellValue(h)).toList());
// Add data rows
// for (var i = 0; i < data.length; i++) {
// final rowMap = data[i];
// final row = <CellValue?>[];
//
// for (var key in keys) {
// dynamic value;
// if (key == 'sno' ||
// key.toLowerCase() == 's.no' ||
// key.toLowerCase() == 'sno.') {
// value = i + 1; // serial number
// } else {
// value = rowMap[key];
// }
//
// if (value == null) {
// row.add(TextCellValue('-'));
// } else if (value is int) {
// row.add(IntCellValue(value));
// } else if (value is double) {
// row.add(DoubleCellValue(value));
// } else {
// row.add(TextCellValue(value.toString()));
// }
// }
//
// sheet.appendRow(row);
// }
// Reverse the data list so latest entries come first
final reversedData = data.reversed.toList();
for (var i = 0; i < reversedData.length; i++) {
final rowMap = reversedData[i];
final row = <CellValue?>[];
for (var key in keys) {
dynamic value;
if (key == 'sno' ||
key.toLowerCase() == 's.no' ||
key.toLowerCase() == 'sno.') {
value = i + 1; // serial number (descending)
} else if (key.toLowerCase() == 'is_active') {
// Handle Active/Inactive display
final rawVal = rowMap[key];
value = (rawVal == 1 || rawVal == '1') ? 'Active' : 'Inactive';
} else {
value = rowMap[key];
}
// Add data
for (var rowData in data) {
var row = <CellValue?>[];
for (var key in headers) {
final value = rowData[key];
if (value == null) { if (value == null) {
row.add(TextCellValue('-')); row.add(TextCellValue('-'));
} else if (value is int) { } else if (value is int) {
@ -116,56 +197,62 @@ class ExcelExporter {
row.add(TextCellValue(value.toString())); row.add(TextCellValue(value.toString()));
} }
} }
sheetObject.appendRow(row);
sheet.appendRow(row);
} }
var bytes = excel.encode()!; final excelBytes = excel.encode();
if (excelBytes == null) throw Exception('Failed to encode Excel file');
if (kIsWeb) { if (kIsWeb) {
// Web: base64 download instead of Blob // Web download
final base64Str = base64Encode(bytes); final base64Str = base64Encode(excelBytes);
final dataUri = "data:application/octet-stream;base64,$base64Str"; final dataUri = 'data:application/octet-stream;base64,$base64Str';
final anchor = html.AnchorElement(href: dataUri) final anchor = html.AnchorElement(href: dataUri)
..setAttribute("download", "$fileName.xlsx") ..setAttribute('download', '$fileName.xlsx')
..click(); ..click();
} else { } else {
// Mobile/Desktop: save file // Mobile/Desktop save + open
final dir = await getApplicationDocumentsDirectory(); final dir = await getApplicationDocumentsDirectory();
final file = File('${dir.path}/$fileName.xlsx'); final filePath = '${dir.path}/$fileName.xlsx';
await file.writeAsBytes(bytes); final file = File(filePath);
await file.writeAsBytes(excelBytes, flush: true);
await OpenFile.open(file.path); await OpenFile.open(file.path);
} }
} catch (e) { } catch (e, st) {
print("Error exporting Excel: $e"); debugPrint('❌ Excel export error: $e\n$st');
rethrow;
} }
} }
} }
// class ExcelExporter { // class ExcelExporter {
// static Future<void> exportToExcel({ // static Future<void> exportToExcel({
// required String sheetName, // required String sheetName,
// required List<Map<String, dynamic>> data, // required List<Map<String, dynamic>> data,
// required List<String> headers, // required List<String> headers,
// required String fileName, // required String fileName,
// required List<String> keys,
// }) async { // }) async {
// try { // try {
// // Create Excel and delete default sheet // // Create Excel
// var excel = Excel.createExcel(); // var excel = Excel.createExcel();
//
// // Rename default sheet
// if (excel.sheets.containsKey('Sheet1')) { // if (excel.sheets.containsKey('Sheet1')) {
// excel.delete('Sheet1'); // excel.rename('Sheet1', sheetName);
// } // }
// //
// // Create your sheet // // Get the sheet
// Sheet sheetObject = excel[sheetName]; // now this is the only sheet // Sheet sheetObject = excel[sheetName]!;
// //
// // Add headers // // Add headers
// sheetObject.appendRow(headers.map((h) => TextCellValue(h)).toList()); // sheetObject.appendRow(keys.map((h) => TextCellValue(h)).toList());
// //
// // Add data // // Add data
// for (var rowData in data) { // for (var rowData in data) {
// var row = <CellValue?>[]; // var row = <CellValue?>[];
// for (var key in headers) { // for (var key in keys) {
// final value = rowData[key]; // final value = rowData[key];
// if (value == null) { // if (value == null) {
// row.add(TextCellValue('-')); // row.add(TextCellValue('-'));
@ -183,13 +270,12 @@ class ExcelExporter {
// var bytes = excel.encode()!; // var bytes = excel.encode()!;
// //
// if (kIsWeb) { // if (kIsWeb) {
// // Web: download // // Web: base64 download instead of Blob
// final blob = html.Blob([bytes]); // final base64Str = base64Encode(bytes);
// final url = html.Url.createObjectUrlFromBlob(blob); // final dataUri = "data:application/octet-stream;base64,$base64Str";
// final anchor = html.AnchorElement(href: url) // final anchor = html.AnchorElement(href: dataUri)
// ..setAttribute("download", "$fileName.xlsx") // ..setAttribute("download", "$fileName.xlsx")
// ..click(); // ..click();
// html.Url.revokeObjectUrl(url);
// } else { // } else {
// // Mobile/Desktop: save file // // Mobile/Desktop: save file
// final dir = await getApplicationDocumentsDirectory(); // final dir = await getApplicationDocumentsDirectory();
@ -202,66 +288,3 @@ class ExcelExporter {
// } // }
// } // }
// } // }
//---------------------------------------------------------------------------
// class ExcelExporter {
// static Future<void> exportToExcel({
// required String sheetName,
// required List<Map<String, dynamic>> data,
// required List<String> headers,
// required String fileName,
// }) async {
// try {
// // var excel = Excel.createExcel();
// // Sheet sheetObject = excel[sheetName];
//
// // Delete default sheet
// var excel = Excel.createExcel();
// excel.delete('Sheet1'); // remove default
// Sheet sheetObject = excel[sheetName];
//
// // Add headers
// sheetObject.appendRow(headers.map((h) => TextCellValue(h)).toList());
//
// // Add data
// for (int i = 0; i < data.length; i++) {
// var row = <CellValue?>[];
// for (var key in headers) {
// final value = data[i][key];
// if (value == null) {
// row.add(TextCellValue('-'));
// } else if (value is int) {
// row.add(IntCellValue(value));
// } else if (value is double) {
// row.add(DoubleCellValue(value));
// } else {
// row.add(TextCellValue(value.toString()));
// }
// }
// sheetObject.appendRow(row);
// }
//
// var bytes = excel.encode()!;
//
// if (kIsWeb) {
// // Web: download as file
// final blob = html.Blob([bytes]);
// final url = html.Url.createObjectUrlFromBlob(blob);
// final anchor = html.AnchorElement(href: url)
// ..setAttribute("download", "$fileName.xlsx")
// ..click();
// html.Url.revokeObjectUrl(url);
// } else {
// // Mobile/Desktop: save to file system
// final dir = await getApplicationDocumentsDirectory();
// final file = File('${dir.path}/$fileName.xlsx');
// await file.writeAsBytes(bytes);
// await OpenFile.open(file.path);
// }
// } catch (e) {
// print("Error exporting Excel: $e");
// }
// }
// }