import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import '../../../../common/extension/extension.dart'; import '../../../../common/theme/theme.dart'; import '../../../../domain/analytic/analytic.dart'; class DailyRevenueChart extends StatelessWidget { final List salesData; const DailyRevenueChart({super.key, required this.salesData}); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: AppColor.textLight.withOpacity(0.08), spreadRadius: 1, blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text( context.lang.daily_revenue, style: AppStyle.lg.copyWith( fontWeight: FontWeight.w700, color: AppColor.textPrimary, ), ), const SizedBox(height: 4), Text( context.lang.daily_revenue_desc, style: AppStyle.sm.copyWith( color: AppColor.textSecondary, fontWeight: FontWeight.w400, ), ), const SizedBox(height: 24), // Bar Chart salesData.isEmpty ? _buildEmptyState() : SizedBox(height: 200, child: _buildBarChart()), ], ), ); } Widget _buildEmptyState() { return SizedBox( height: 200, child: Center( child: Builder( builder: (context) => Text( context.lang.no_data_yet, style: AppStyle.md.copyWith(color: AppColor.textSecondary), ), ), ), ); } Widget _buildBarChart() { final maxValue = _getMaxValue(); return BarChart( BarChartData( alignment: BarChartAlignment.spaceAround, maxY: maxValue, minY: 0, barTouchData: BarTouchData( enabled: true, touchTooltipData: BarTouchTooltipData( tooltipPadding: const EdgeInsets.all(8), getTooltipItem: (group, groupIndex, rod, rodIndex) { if (groupIndex < salesData.length) { final sale = salesData[groupIndex]; return BarTooltipItem( sale.sales.currencyFormatRp, const TextStyle( color: AppColor.textWhite, fontWeight: FontWeight.bold, fontSize: 12, ), ); } return null; }, ), ), titlesData: FlTitlesData( show: true, topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 30, getTitlesWidget: (value, meta) { final index = value.toInt(); if (index >= 0 && index < salesData.length) { final date = DateTime.tryParse(salesData[index].date); final dayName = date != null ? _getShortDayName(date.weekday) : ''; return Padding( padding: const EdgeInsets.only(top: 8), child: Text( dayName, style: AppStyle.sm.copyWith( color: AppColor.textSecondary, fontWeight: FontWeight.w500, ), ), ); } return const SizedBox.shrink(); }, ), ), ), gridData: FlGridData(show: false), borderData: FlBorderData(show: false), barGroups: _buildBarGroups(maxValue), ), ); } List _buildBarGroups(double maxValue) { return salesData.asMap().entries.map((entry) { final index = entry.key; final sale = entry.value; final value = sale.sales.toDouble(); // Gradient from green to lighter green for higher values final ratio = maxValue > 0 ? value / maxValue : 0.0; final color = Color.lerp( AppColor.success, AppColor.success.withGreen(230), ratio, )!; return BarChartGroupData( x: index, barRods: [ BarChartRodData( toY: value, width: 28, borderRadius: BorderRadius.circular(8), gradient: LinearGradient( colors: [color, color.withOpacity(0.8)], begin: Alignment.bottomCenter, end: Alignment.topCenter, ), ), ], ); }).toList(); } double _getMaxValue() { if (salesData.isEmpty) return 1000000; final maxValue = salesData .map((e) => e.sales.toDouble()) .reduce((a, b) => a > b ? a : b); return maxValue * 1.2; } String _getShortDayName(int weekday) { const days = ['Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab', 'Min']; return days[weekday - 1]; } }