import 'package:flutter/material.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; import '../../../transactions/data/models.dart'; import '../../../../core/theme/nature_colors.dart'; import 'day_wise_spending_chart.dart'; import 'category_spending_chart.dart'; class StatisticsTab extends StatefulWidget { final List transactions; final List wallets; final List categories; final String selectedFilter; final DateTime startDate; final DateTime endDate; final VoidCallback onPickCustomDateRange; final Function(String) onFilterChanged; final Future Function() onRefresh; final List filters; const StatisticsTab({ super.key, required this.transactions, required this.wallets, required this.categories, required this.selectedFilter, required this.startDate, required this.endDate, required this.onPickCustomDateRange, required this.onFilterChanged, required this.onRefresh, required this.filters, }); @override State createState() => _StatisticsTabState(); } class _StatisticsTabState extends State { String _selectedNature = 'EXPENSE'; Widget _buildTotalCard( String title, double amount, Color color, IconData icon, ) { final isDark = Theme.of(context).brightness == Brightness.dark; return Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide( color: Theme.of(context).dividerColor.withOpacity(isDark ? 0.1 : 0.2), ), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ CircleAvatar( backgroundColor: color.withOpacity(0.1), radius: 16, child: Icon(icon, color: color, size: 16), ), const SizedBox(width: 8), Expanded( child: Text( title, style: const TextStyle( fontSize: 12, color: Colors.grey, fontWeight: FontWeight.bold, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), const SizedBox(height: 12), Text( 'Rs. ${amount.toStringAsFixed(0)}', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: color, ), ), ], ), ), ); } @override Widget build(BuildContext context) { // Compute totals final totalIncome = widget.transactions .where( (t) => t.type == 'INCOME' || (t.type == 'TRANSFER' && t.fromWalletId == null), ) .fold(0.0, (s, t) => s + t.amount); final totalExpense = widget.transactions .where( (t) => t.type == 'EXPENSE' || (t.type == 'TRANSFER' && t.toWalletId == null), ) .fold(0.0, (s, t) => s + t.amount); final totalInvestment = widget.transactions .where((t) => t.type == 'INVESTMENT') .fold(0.0, (s, t) => s + t.amount); double totalPayablesPeriod = 0.0; double totalReceivablesPeriod = 0.0; for (var t in widget.transactions) { if (t.toWalletId != null) { final w = widget.wallets.where((w) => w.id == t.toWalletId); if (w.isNotEmpty) { final nature = w.first.nature; if (nature == 'PAYABLES' || nature == 'LOAN') { totalPayablesPeriod += t.amount; } else if (nature == 'RECEIVABLES' || nature == 'LENDING') { totalReceivablesPeriod += t.amount; } } } } Color barColor = NatureColors.getColor(_selectedNature); return RefreshIndicator( onRefresh: widget.onRefresh, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( children: widget.filters.map((f) { final isSelected = widget.selectedFilter == f; return Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(f), selected: isSelected, onSelected: (val) { if (val) { if (f == 'Custom') { widget.onPickCustomDateRange(); } else { widget.onFilterChanged(f); } } }, ), ); }).toList(), ), ), if (widget.selectedFilter == 'Custom') Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), child: Text( '${widget.startDate.day} ${widget.startDate.month} - ${widget.endDate.day} ${widget.endDate.month}', style: const TextStyle( fontWeight: FontWeight.bold, color: Colors.grey, ), ), ), Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Analytics', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ), ), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 0, ), decoration: BoxDecoration( color: barColor.withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: DropdownButton( value: _selectedNature, underline: const SizedBox(), icon: Icon(Icons.arrow_drop_down, color: barColor), style: TextStyle( color: barColor, fontWeight: FontWeight.bold, ), items: const [ DropdownMenuItem( value: 'EXPENSE', child: Text('Expense'), ), DropdownMenuItem( value: 'INCOME', child: Text('Income'), ), DropdownMenuItem( value: 'PAYABLES', child: Text('Payables'), ), DropdownMenuItem( value: 'RECEIVABLES', child: Text('Receivables'), ), DropdownMenuItem( value: 'INVESTMENTS', child: Text('Investments'), ), ], onChanged: (val) { if (val != null) { setState(() => _selectedNature = val); } }, ), ), ], ), const SizedBox(height: 24), if (widget.transactions.isEmpty) Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), side: BorderSide( color: Theme.of(context).dividerColor.withOpacity( Theme.of(context).brightness == Brightness.dark ? 0.1 : 0.2, ), ), ), child: const Padding( padding: EdgeInsets.all(32.0), child: Center( child: Text( 'No transactions in this period.', style: TextStyle(color: Colors.grey), ), ), ), ) else ...[ DayWiseSpendingChart( transactions: widget.transactions, wallets: widget.wallets, selectedNature: _selectedNature, startDate: widget.startDate, endDate: widget.endDate, ), const SizedBox(height: 16), CategorySpendingChart( transactions: widget.transactions, categories: widget.categories, selectedNature: _selectedNature, ), ], const SizedBox(height: 32), const Text( 'Summary Totals', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), GridView.count( crossAxisCount: 2, crossAxisSpacing: 12, mainAxisSpacing: 12, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), childAspectRatio: 1.5, children: [ _buildTotalCard( 'Income', totalIncome, NatureColors.getColor('INCOME'), LucideIcons.arrowDown, ), _buildTotalCard( 'Expense', totalExpense, NatureColors.getColor('EXPENSE'), LucideIcons.arrowUp, ), _buildTotalCard( 'Investment', totalInvestment, NatureColors.getColor('INVESTMENTS'), LucideIcons.trendingUp, ), _buildTotalCard( 'Payables', totalPayablesPeriod, NatureColors.getColor('PAYABLES'), LucideIcons.alertCircle, ), _buildTotalCard( 'Receivables', totalReceivablesPeriod, NatureColors.getColor('RECEIVABLES'), LucideIcons.arrowDownLeft, ), ], ), const SizedBox(height: 32), ], ), ), ], ), ), ); } }