import 'dart:developer'; import 'package:enaklo_pos/core/components/date_range_picker.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/utils/helper_pdf_service.dart'; import 'package:enaklo_pos/core/utils/permession_handler.dart'; import 'package:enaklo_pos/core/utils/transaction_report.dart'; import 'package:enaklo_pos/presentation/report/blocs/category_report/category_report_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/inventory_report/inventory_report_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/profit_loss/profit_loss_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/report/report_bloc.dart'; import 'package:enaklo_pos/presentation/report/widgets/category_report_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/dashboard_analytic_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/inventory_report_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/profit_loss_widget.dart'; import 'package:enaklo_pos/presentation/sales/pages/sales_page.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import 'package:enaklo_pos/core/utils/date_formatter.dart'; import 'package:enaklo_pos/presentation/report/blocs/item_sales_report/item_sales_report_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/payment_method_report/payment_method_report_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/product_sales/product_sales_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/summary/summary_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/transaction_report/transaction_report_bloc.dart'; import 'package:enaklo_pos/presentation/report/widgets/item_sales_report_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/payment_method_report_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/product_analytic_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/report_menu.dart'; import 'package:enaklo_pos/presentation/report/widgets/report_title.dart'; import 'package:flutter/material.dart'; import 'package:enaklo_pos/presentation/report/widgets/transaction_report_widget.dart'; import '../../../core/components/spaces.dart'; class ReportPage extends StatefulWidget { const ReportPage({super.key}); @override State createState() => _ReportPageState(); } class _ReportPageState extends State { int selectedMenu = 0; String title = 'Ringkasan Laporan Penjualan'; DateTime fromDate = DateTime.now().subtract(const Duration(days: 30)); DateTime toDate = DateTime.now(); @override void initState() { super.initState(); context.read().add( SummaryEvent.getSummary(fromDate, toDate), ); context.read().add( ReportEvent.get(startDate: fromDate, endDate: toDate), ); } onDateChanged(DateTime? startDate, DateTime? endDate) { setState(() { fromDate = startDate ?? fromDate; toDate = endDate ?? toDate; }); context.read().add( ReportEvent.get(startDate: fromDate, endDate: toDate), ); if (selectedMenu == 0) { context.read().add( SummaryEvent.getSummary(fromDate, toDate), ); } if (selectedMenu == 2) { context.read().add( ItemSalesReportEvent.getItemSales( startDate: fromDate, endDate: toDate), ); } if (selectedMenu == 3) { context.read().add( ProductSalesEvent.getProductSales( fromDate, toDate, ), ); } if (selectedMenu == 4) { context.read().add( PaymentMethodReportEvent.getPaymentMethodReport( startDate: fromDate, endDate: toDate, ), ); } if (selectedMenu == 5) { context.read().add( ProfitLossEvent.getProfitLoss( fromDate, toDate, ), ); } if (selectedMenu == 6) { context.read().add( InventoryReportEvent.get( startDate: fromDate, endDate: toDate, ), ); } if (selectedMenu == 7) { context.read().add( CategoryReportEvent.get( startDate: fromDate, endDate: toDate, ), ); } } @override Widget build(BuildContext context) { String searchDateFormatted = '${fromDate.toFormattedDate2()} - ${toDate.toFormattedDate2()}'; return Scaffold( backgroundColor: AppColors.background, body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ReportTitle( searchDateFormatted: searchDateFormatted, actionWidget: [ InkWell( onTap: () { DateRangePickerModal.show( context: context, initialEndDate: toDate, initialStartDate: fromDate, primaryColor: AppColors.primary, onChanged: onDateChanged, ); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(6.0), border: Border.all( color: AppColors.stroke, )), child: Icon( Icons.calendar_month_outlined, color: AppColors.primary, size: 28, ), ), ), const SpaceWidth(12.0), BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => SizedBox.shrink(), loading: () => SizedBox( height: 24, width: 24, child: const CircularProgressIndicator(), ), loaded: (outlet, categoryAnalyticData, profitLossData, paymentMethodAnalyticData, productAnalyticData) => InkWell( onTap: () async { try { final status = await PermessionHelper().checkPermission(); if (status) { final pdfFile = await TransactionReport.previewPdf( outlet: outlet, searchDateFormatted: searchDateFormatted, categoryAnalyticData: categoryAnalyticData, profitLossData: profitLossData, paymentMethodAnalyticData: paymentMethodAnalyticData, productAnalyticData: productAnalyticData, ); log("pdfFile: $pdfFile"); await HelperPdfService.openFile(pdfFile); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Storage permission is required to save PDF'), backgroundColor: Colors.red, ), ); } } catch (e) { log("Error generating PDF: $e"); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Failed to generate PDF: $e'), backgroundColor: Colors.red, ), ); } }, child: Container( padding: EdgeInsets.symmetric( horizontal: 12.0, vertical: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(6.0), border: Border.all( color: AppColors.stroke, )), child: Icon( Icons.download, color: AppColors.primary, size: 28, ), ), ), ); }, ), ], ), Expanded( child: Row( children: [ // LEFT CONTENT Expanded( flex: 2, child: Material( color: AppColors.white, child: Align( alignment: Alignment.topLeft, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ReportMenu( label: 'Ringkasan Laporan Penjualan', subtitle: 'Ringkasan total penjualan dalam periode tertentu.', icon: Icons.insert_drive_file_outlined, onPressed: () { selectedMenu = 0; title = 'Ringkasan Laporan Penjualan'; setState(() {}); context.read().add( SummaryEvent.getSummary(fromDate, toDate), ); log("Date ${DateFormatter.formatDateTime(fromDate)}"); }, isActive: selectedMenu == 0, ), ReportMenu( label: 'Laporan Transaksi', subtitle: 'Menampilkan riwayat lengkap semua transaksi yang telah dilakukan.', icon: Icons.receipt_long_outlined, onPressed: () { context.push(SalesPage(status: 'completed')); }, isActive: selectedMenu == 1, ), ReportMenu( label: 'Laporan Penjualan Item', subtitle: 'Laporan penjualan berdasarkan masing-masing item atau produk.', icon: Icons.inventory_2_outlined, onPressed: () { selectedMenu = 2; title = 'Laporan Penjualan Item'; setState(() {}); context.read().add( ItemSalesReportEvent.getItemSales( startDate: fromDate, endDate: toDate), ); }, isActive: selectedMenu == 2, ), ReportMenu( label: 'Laporan Penjualan Produk', subtitle: 'Laporan penjualan berdasarkan masing-masing produk.', icon: Icons.bar_chart_outlined, onPressed: () { selectedMenu = 3; title = 'Laporan Penjualan Produk'; setState(() {}); context.read().add( ProductSalesEvent.getProductSales( fromDate, toDate, ), ); }, isActive: selectedMenu == 3, ), ReportMenu( label: 'Laporan Metode Pembayaran', subtitle: 'Laporan metode pembayaran yang digunakan.', icon: Icons.payment_outlined, onPressed: () { selectedMenu = 4; title = 'Laporan Metode Pembayaran'; setState(() {}); context.read().add( PaymentMethodReportEvent .getPaymentMethodReport( startDate: fromDate, endDate: toDate, ), ); }, isActive: selectedMenu == 4, ), ReportMenu( label: 'Laporan Untung Rugi', subtitle: 'Laporan untung rugi penjualan.', icon: Icons.trending_down, onPressed: () { selectedMenu = 5; title = 'Laporan Untung Rugi'; setState(() {}); context.read().add( ProfitLossEvent.getProfitLoss( fromDate, toDate, ), ); }, isActive: selectedMenu == 5, ), ReportMenu( label: 'Laporan Inventori', subtitle: 'Laporan inventori produk', icon: Icons.archive_outlined, onPressed: () { selectedMenu = 6; title = 'Laporan Inventori'; setState(() {}); context.read().add( InventoryReportEvent.get( startDate: fromDate, endDate: toDate, ), ); }, isActive: selectedMenu == 6, ), ReportMenu( label: 'Laporan Kategori', subtitle: 'Laporan kategori produk', icon: Icons.category_outlined, onPressed: () { selectedMenu = 7; title = 'Laporan Kategori'; setState(() {}); context.read().add( CategoryReportEvent.get( startDate: fromDate, endDate: toDate, ), ); }, isActive: selectedMenu == 7, ), ], ), ), ), ), ), // RIGHT CONTENT Expanded( flex: 4, child: selectedMenu == 0 ? BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text(message); }, success: (data) { return DashboardAnalyticWidget( data: data, title: title, searchDateFormatted: searchDateFormatted, ); }, ); }, ) : selectedMenu == 1 ? BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text(message); }, loaded: (transactionReport) { return TransactionReportWidget( transactionReport: transactionReport, title: title, searchDateFormatted: searchDateFormatted, headerWidgets: _getTitleReportPageWidget(), ); }, ); }, ) : selectedMenu == 2 ? BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text(message); }, loaded: (itemSales) { return ItemSalesReportWidget( sales: itemSales, title: title, searchDateFormatted: searchDateFormatted, headerWidgets: _getItemSalesPageWidget(), ); }, ); }, ) : selectedMenu == 3 ? BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text(message); }, success: (products) { return ProductAnalyticsWidget( title: title, searchDateFormatted: searchDateFormatted, productData: products, ); }, ); }, ) : selectedMenu == 4 ? BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text(message); }, loaded: (paymentMethodData) { return PaymentMethodReportWidget( paymentMethodData: paymentMethodData, title: title, searchDateFormatted: searchDateFormatted, headerWidgets: _getPaymentMethodPageWidget(), ); }, ); }, ) : selectedMenu == 5 ? BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text(message); }, success: (data) { return ProfitLossWidget( data: data, title: title, searchDateFormatted: searchDateFormatted, ); }, ); }, ) : selectedMenu == 6 ? BlocBuilder< InventoryReportBloc, InventoryReportState>( builder: (context, state) { return state.maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text(message); }, loaded: (data) { return InventoryReportWidget( title: title, searchDateFormatted: searchDateFormatted, inventory: data, ); }, ); }, ) : selectedMenu == 7 ? BlocBuilder< CategoryReportBloc, CategoryReportState>( builder: (context, state) { return state .maybeWhen( orElse: () => const Center( child: CircularProgressIndicator(), ), error: (message) { return Text( message); }, loaded: (data) { return CategoryReportWidget( title: title, searchDateFormatted: searchDateFormatted, categoryAnalyticData: data, ); }, ); }, ) : const SizedBox.shrink()), ], ), ), ], ), ); } List _getTitleReportPageWidget() { return [ _getTitleItemWidget('ID', 120), _getTitleItemWidget('Total', 100), _getTitleItemWidget('Sub Total', 100), _getTitleItemWidget('Tax', 100), _getTitleItemWidget('Disocunt', 100), _getTitleItemWidget('Service', 100), _getTitleItemWidget('Total Item', 100), _getTitleItemWidget('Cashier', 180), _getTitleItemWidget('Time', 200), ]; } List _getItemSalesPageWidget() { return [ _getTitleItemWidget('ID', 80), _getTitleItemWidget('Order', 100), _getTitleItemWidget('Product', 200), _getTitleItemWidget('Qty', 60), _getTitleItemWidget('Price', 150), _getTitleItemWidget('Total Price', 160), ]; } List _getPaymentMethodPageWidget() { return [ _getTitleItemWidget('Payment Method', 180), _getTitleItemWidget('Total Amount', 180), _getTitleItemWidget('Transaction Count', 180), ]; } Widget _getTitleItemWidget(String label, double width) { return Container( width: width, height: 56, color: AppColors.primary, alignment: Alignment.centerLeft, child: Center( child: Text( label, style: TextStyle( color: Colors.white, ), ), ), ); } }