import 'package:flutter/material.dart'; import 'package:line_icons/line_icons.dart'; import 'package:intl/intl.dart'; import '../../../../common/extension/extension.dart'; import '../../../../common/theme/theme.dart'; import '../../../../domain/analytic/analytic.dart'; import '../../../components/widgets/empty_widget.dart'; class FinanceCategory extends StatelessWidget { final List categories; const FinanceCategory({super.key, required this.categories}); @override Widget build(BuildContext context) { final totalRevenue = _calculateTotalRevenue(); final sortedCategories = _sortCategoriesByRevenue(); return Container( margin: const EdgeInsets.all(16), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: AppColor.textLight.withOpacity(0.1), spreadRadius: 1, blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppColor.secondary.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: const Icon( LineIcons.pieChart, color: AppColor.secondary, size: 20, ), ), const SizedBox(width: 12), Text( 'Kategori Penjualan', style: AppStyle.lg.copyWith(fontWeight: FontWeight.bold), ), ], ), const SizedBox(height: 20), // Show empty state if no categories if (categories.isEmpty) _buildEmptyState() else ...sortedCategories.asMap().entries.map( (entry) => _buildCategoryItem( entry.value, _calculatePercentage(entry.value.totalRevenue, totalRevenue), _getCategoryColor(entry.key), ), ), ], ), ); } Widget _buildCategoryItem( CategoryAnalyticItem category, double percentage, Color color, ) { return Container( margin: const EdgeInsets.only(bottom: 16), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Row( children: [ Container( width: 12, height: 12, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(6), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( category.categoryName, style: AppStyle.md.copyWith( fontWeight: FontWeight.w600, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: 2), Text( '${category.productCount} produk • ${category.orderCount} pesanan', style: AppStyle.xs.copyWith( color: AppColor.textSecondary, ), ), ], ), ), ], ), ), const SizedBox(width: 12), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( category.totalRevenue.currencyFormatRp, style: AppStyle.md.copyWith( fontWeight: FontWeight.bold, color: color, ), ), Text( '${NumberFormat('#,###', 'id_ID').format(category.totalQuantity)} unit', style: AppStyle.xs.copyWith(color: AppColor.textSecondary), ), ], ), ], ), const SizedBox(height: 8), LinearProgressIndicator( value: percentage / 100, backgroundColor: AppColor.borderLight, valueColor: AlwaysStoppedAnimation(color), minHeight: 6, ), const SizedBox(height: 4), Align( alignment: Alignment.centerRight, child: Text( '${percentage.toStringAsFixed(1)}%', style: AppStyle.xs.copyWith(color: AppColor.textSecondary), ), ), ], ), ); } Widget _buildEmptyState() { return EmptyWidget( title: 'Belum ada data kategori', message: 'Data kategori penjualan akan muncul di sini', ); } // Helper methods int _calculateTotalRevenue() { return categories.fold(0, (sum, category) => sum + category.totalRevenue); } List _sortCategoriesByRevenue() { final sorted = List.from(categories); sorted.sort((a, b) => b.totalRevenue.compareTo(a.totalRevenue)); return sorted; } double _calculatePercentage(int categoryRevenue, int totalRevenue) { if (totalRevenue == 0) return 0; return (categoryRevenue / totalRevenue) * 100; } Color _getCategoryColor(int index) { // Predefined color palette for categories const colors = [ AppColor.primary, AppColor.secondary, AppColor.success, AppColor.warning, AppColor.error, AppColor.info, ]; // Generate additional colors if needed if (index < colors.length) { return colors[index]; } else { // Generate colors based on index for unlimited categories final hue = (index * 137.5) % 360; // Golden angle approximation return HSLColor.fromAHSL(1.0, hue, 0.7, 0.5).toColor(); } } }