feat: inventory report

This commit is contained in:
efrilm
2025-08-19 17:05:55 +07:00
parent 50934bfed9
commit 1aa65d1732
17 changed files with 1772 additions and 106 deletions
@@ -1,16 +1,34 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../../../application/report/inventory_report/inventory_report_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../common/utils/pdf_service.dart';
import '../../../common/utils/permission.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import '../../components/field/date_range_picker_field.dart';
import '../../components/report/inventory_report.dart';
import '../../components/toast/flushbar.dart';
@RoutePage()
class DownloadReportPage extends StatefulWidget {
class DownloadReportPage extends StatefulWidget implements AutoRouteWrapper {
const DownloadReportPage({super.key});
@override
State<DownloadReportPage> createState() => _DownloadReportPageState();
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) =>
getIt<InventoryReportBloc>()..add(InventoryReportEvent.fetchedOutlet()),
child: this,
);
}
class _DownloadReportPageState extends State<DownloadReportPage>
@@ -26,10 +44,10 @@ class _DownloadReportPageState extends State<DownloadReportPage>
DateTime? _transactionEndDate;
DateTime? _inventoryStartDate;
DateTime? _inventoryEndDate;
DateTime? _salesStartDate;
DateTime? _salesEndDate;
DateTime? _customerStartDate;
DateTime? _customerEndDate;
// DateTime? _salesStartDate;
// DateTime? _salesEndDate;
// DateTime? _customerStartDate;
// DateTime? _customerEndDate;
@override
void initState() {
@@ -76,28 +94,9 @@ class _DownloadReportPageState extends State<DownloadReportPage>
DateTime? endDate,
) {
if (startDate == null || endDate == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Please select both start and end dates'),
backgroundColor: AppColor.error,
),
);
AppFlushbar.showError(context, 'Please select both start and end dates');
return;
}
// Implement download logic here
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Downloading $reportType from ${_formatDate(startDate)} to ${_formatDate(endDate)}',
),
backgroundColor: AppColor.success,
),
);
}
String _formatDate(DateTime date) {
return '${date.day}/${date.month}/${date.year}';
}
@override
@@ -139,6 +138,7 @@ class _DownloadReportPageState extends State<DownloadReportPage>
],
startDate: _transactionStartDate,
endDate: _transactionEndDate,
isLoading: false,
onDateRangeChanged: (start, end) {
setState(() {
_transactionStartDate = start;
@@ -156,79 +156,115 @@ class _DownloadReportPageState extends State<DownloadReportPage>
const SizedBox(height: 20),
// Inventory Report Card
_ReportOptionCard(
title: 'Inventory Report',
subtitle:
'Export inventory and stock data with trends',
icon: Icons.inventory_2_outlined,
gradient: const [
AppColor.secondary,
AppColor.secondaryLight,
],
startDate: _inventoryStartDate,
endDate: _inventoryEndDate,
onDateRangeChanged: (start, end) {
setState(() {
_inventoryStartDate = start;
_inventoryEndDate = end;
});
BlocBuilder<InventoryReportBloc, InventoryReportState>(
builder: (context, state) {
return _ReportOptionCard(
title: 'Inventory Report',
subtitle:
'Export inventory and stock data with trends',
icon: Icons.inventory_2_outlined,
gradient: const [
AppColor.secondary,
AppColor.secondaryLight,
],
startDate: _inventoryStartDate,
endDate: _inventoryEndDate,
isLoading: state.isFetching,
onDateRangeChanged: (start, end) {
setState(() {
_inventoryStartDate = start;
_inventoryEndDate = end;
});
if (start != null || end != null) {
context.read<InventoryReportBloc>().add(
InventoryReportEvent.fetchedInventory(
start!,
end!,
),
);
}
},
onDownload: () async {
try {
final status = await PermessionHelper()
.checkPermission();
if (status) {
final pdfFile =
await InventoryReport.previewPdf(
searchDateFormatted:
"${_inventoryStartDate?.toServerDate} - ${_inventoryEndDate?.toServerDate}",
inventory: state.inventoryAnalytic,
outlet: state.outlet,
);
log("pdfFile: $pdfFile");
await HelperPdfService.openFile(pdfFile);
} else {
AppFlushbar.showError(
context,
'Storage permission is required to save PDF',
);
}
} catch (e) {
log("Error generating PDF: $e");
AppFlushbar.showError(
context,
'Failed to generate PDF: $e',
);
}
},
delay: 400,
);
},
onDownload: () => _downloadReport(
'Inventory Report',
_inventoryStartDate,
_inventoryEndDate,
),
delay: 400,
),
const SizedBox(height: 20),
// Sales Report Card
_ReportOptionCard(
title: 'Sales Report',
subtitle: 'Export sales performance and revenue data',
icon: Icons.trending_up_outlined,
gradient: const [AppColor.info, Color(0xFF64B5F6)],
startDate: _salesStartDate,
endDate: _salesEndDate,
onDateRangeChanged: (start, end) {
setState(() {
_salesStartDate = start;
_salesEndDate = end;
});
},
onDownload: () => _downloadReport(
'Sales Report',
_salesStartDate,
_salesEndDate,
),
delay: 600,
),
// _ReportOptionCard(
// title: 'Sales Report',
// subtitle: 'Export sales performance and revenue data',
// icon: Icons.trending_up_outlined,
// gradient: const [AppColor.info, Color(0xFF64B5F6)],
// startDate: _salesStartDate,
// endDate: _salesEndDate,
// onDateRangeChanged: (start, end) {
// setState(() {
// _salesStartDate = start;
// _salesEndDate = end;
// });
// },
// onDownload: () => _downloadReport(
// 'Sales Report',
// _salesStartDate,
// _salesEndDate,
// ),
// delay: 600,
// ),
const SizedBox(height: 20),
// const SizedBox(height: 20),
// Customer Report Card
_ReportOptionCard(
title: 'Customer Report',
subtitle:
'Export customer data and behavior analytics',
icon: Icons.people_outline,
gradient: const [AppColor.warning, Color(0xFFFFB74D)],
startDate: _customerStartDate,
endDate: _customerEndDate,
onDateRangeChanged: (start, end) {
setState(() {
_customerStartDate = start;
_customerEndDate = end;
});
},
onDownload: () => _downloadReport(
'Customer Report',
_customerStartDate,
_customerEndDate,
),
delay: 800,
),
// // Customer Report Card
// _ReportOptionCard(
// title: 'Customer Report',
// subtitle:
// 'Export customer data and behavior analytics',
// icon: Icons.people_outline,
// gradient: const [AppColor.warning, Color(0xFFFFB74D)],
// startDate: _customerStartDate,
// endDate: _customerEndDate,
// onDateRangeChanged: (start, end) {
// setState(() {
// _customerStartDate = start;
// _customerEndDate = end;
// });
// },
// onDownload: () => _downloadReport(
// 'Customer Report',
// _customerStartDate,
// _customerEndDate,
// ),
// delay: 800,
// ),
],
),
),
@@ -253,6 +289,7 @@ class _ReportOptionCard extends StatefulWidget {
final DateTime? endDate;
final Function(DateTime? startDate, DateTime? endDate) onDateRangeChanged;
final VoidCallback onDownload;
final bool isLoading;
final int delay;
const _ReportOptionCard({
@@ -265,6 +302,7 @@ class _ReportOptionCard extends StatefulWidget {
required this.onDateRangeChanged,
required this.onDownload,
required this.delay,
required this.isLoading,
});
@override
@@ -431,23 +469,41 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
),
elevation: 0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.download_rounded,
color: widget.gradient.first,
),
const SizedBox(width: 8),
Text(
'Download Report',
style: AppStyle.md.copyWith(
color: widget.gradient.first,
fontWeight: FontWeight.bold,
child: widget.isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SpinKitCircle(
color: widget.gradient.first,
size: 24,
),
const SizedBox(width: 8),
Text(
'Loading',
style: AppStyle.md.copyWith(
color: widget.gradient.first,
fontWeight: FontWeight.bold,
),
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.download_rounded,
color: widget.gradient.first,
),
const SizedBox(width: 8),
Text(
'Download Report',
style: AppStyle.md.copyWith(
color: widget.gradient.first,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
),
],