// lib/app/widgets/history_grafik_card.dart import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; import '../models/chart_data_point.dart'; // Import model yang terpisah class HistoryGrafikCard extends StatelessWidget { final List dataPoints; // Ubah dari dynamic ke List final VoidCallback? onBookmarkTap; const HistoryGrafikCard({ super.key, required this.dataPoints, this.onBookmarkTap, }); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[200]!), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 0, blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFFE3F2FD), borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.insert_chart_outlined, size: 20, color: Color(0xFF2196F3), ), ), const SizedBox(width: 12), const Text( 'Grafik Infus Pasien', style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), ), ], ), ], ), const SizedBox(height: 20), // FL Chart SizedBox( height: 180, child: LineChart( LineChartData( gridData: FlGridData( show: true, drawVerticalLine: false, horizontalInterval: 5, getDrawingHorizontalLine: (value) { return FlLine(color: Colors.grey[200]!, strokeWidth: 1); }, ), titlesData: FlTitlesData( show: true, rightTitles: const AxisTitles( sideTitles: SideTitles(showTitles: false), ), topTitles: const AxisTitles( sideTitles: SideTitles(showTitles: false), ), bottomTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, reservedSize: 30, interval: 1, getTitlesWidget: (double value, TitleMeta meta) { return Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( '${value.toInt()}:00', style: TextStyle( color: Colors.grey[600], fontWeight: FontWeight.w500, fontSize: 10, ), ), ); }, ), ), leftTitles: AxisTitles( sideTitles: SideTitles( showTitles: true, interval: 5, reservedSize: 35, getTitlesWidget: (double value, TitleMeta meta) { return Text( '${value.toInt()}', style: TextStyle( color: Colors.grey[600], fontWeight: FontWeight.w500, fontSize: 11, ), ); }, ), ), ), borderData: FlBorderData( show: true, border: Border( left: BorderSide(color: Colors.grey[300]!), bottom: BorderSide(color: Colors.grey[300]!), ), ), minX: 8, maxX: 17, minY: 20, maxY: 40, lineBarsData: [ LineChartBarData( spots: dataPoints .map( (point) => FlSpot( point.hour.toDouble(), point.dropsPerMinute, ), ) .toList(), isCurved: true, gradient: const LinearGradient( colors: [Color(0xFF2196F3), Color(0xFF1976D2)], ), barWidth: 3, isStrokeCapRound: true, dotData: FlDotData( show: true, getDotPainter: (spot, percent, barData, index) { return FlDotCirclePainter( radius: 4, color: Colors.white, strokeWidth: 2, strokeColor: const Color(0xFF2196F3), ); }, ), belowBarData: BarAreaData( show: true, gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ const Color(0xFF2196F3).withOpacity(0.3), const Color(0xFF2196F3).withOpacity(0.0), ], ), ), ), ], lineTouchData: LineTouchData( enabled: true, touchTooltipData: LineTouchTooltipData( getTooltipColor: (touchedSpot) => const Color(0xFF2196F3), tooltipBorder: const BorderSide( color: Color(0xFF1976D2), width: 1, ), tooltipPadding: const EdgeInsets.all(8), tooltipMargin: 8, getTooltipItems: (List touchedBarSpots) { return touchedBarSpots.map((barSpot) { return LineTooltipItem( '${barSpot.y.toInt()} tpm\n${barSpot.x.toInt()}:00', const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12, ), ); }).toList(); }, ), ), ), ), ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 12, height: 3, decoration: BoxDecoration( color: const Color(0xFF2196F3), borderRadius: BorderRadius.circular(2), ), ), const SizedBox(width: 6), Text( 'Tetes per Menit', style: TextStyle( fontSize: 11, color: Colors.grey[600], fontWeight: FontWeight.w500, ), ), ], ), ], ), ); } }