111 lines
3.4 KiB
TypeScript
111 lines
3.4 KiB
TypeScript
import React, { useMemo } from 'react';
|
|
import {
|
|
BarChart,
|
|
Bar,
|
|
XAxis,
|
|
YAxis,
|
|
CartesianGrid,
|
|
Tooltip,
|
|
Legend,
|
|
ResponsiveContainer,
|
|
} from 'recharts';
|
|
import { FeedSackLogEntry, FeedSackColumnConfig } from '../../types/counting.ts';
|
|
|
|
interface FeedTrendChartProps {
|
|
data: FeedSackLogEntry[];
|
|
cycleStartDate: Date;
|
|
currentDay: number;
|
|
columnConfig: FeedSackColumnConfig[];
|
|
}
|
|
|
|
const FeedTrendChart: React.FC<FeedTrendChartProps> = ({
|
|
data,
|
|
cycleStartDate,
|
|
currentDay,
|
|
columnConfig,
|
|
}) => {
|
|
const cameraNames = useMemo(() => columnConfig.map((c) => c.cameraName), [columnConfig]);
|
|
|
|
const chartData = useMemo(() => {
|
|
const cycleStart = new Date(cycleStartDate);
|
|
cycleStart.setHours(0, 0, 0, 0);
|
|
|
|
const cycleEnd = new Date(cycleStart);
|
|
cycleEnd.setDate(cycleStart.getDate() + currentDay);
|
|
cycleEnd.setHours(23, 59, 59, 999);
|
|
|
|
// Initialize daily buckets
|
|
const dailyData: { [key: number]: Record<string, any> } = {};
|
|
for (let d = 0; d <= currentDay; d++) {
|
|
const date = new Date(cycleStart);
|
|
date.setDate(cycleStart.getDate() + d);
|
|
const formattedDate = date.toLocaleDateString('id-ID', { day: '2-digit', month: 'short' });
|
|
|
|
const entry: Record<string, any> = { day: `H${d}`, date: formattedDate };
|
|
cameraNames.forEach((name) => {
|
|
entry[name] = 0;
|
|
});
|
|
dailyData[d] = entry;
|
|
}
|
|
|
|
// Aggregate data by day
|
|
data.forEach((log) => {
|
|
if (log.timestamp >= cycleStart && log.timestamp <= cycleEnd) {
|
|
const diffTime = log.timestamp.getTime() - cycleStart.getTime();
|
|
const dayNumber = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
|
|
|
if (dayNumber >= 0 && dayNumber <= currentDay && dailyData[dayNumber]) {
|
|
if (log.cameraName && cameraNames.includes(log.cameraName)) {
|
|
dailyData[dayNumber][log.cameraName] += log.count;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return Object.values(dailyData);
|
|
}, [data, cycleStartDate, currentDay, cameraNames]);
|
|
|
|
return (
|
|
<div className="bg-white p-6 rounded-xl shadow-sm">
|
|
<h2 className="text-xl font-bold text-gray-800 mb-4">Tren Harian Karung Pakan</h2>
|
|
<div className="h-60">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<BarChart data={chartData} margin={{ top: 5, right: 20, left: -15, bottom: 5 }}>
|
|
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" />
|
|
<XAxis
|
|
dataKey="date"
|
|
fontSize={11}
|
|
tick={{ fill: '#6b7280' }}
|
|
angle={-45}
|
|
textAnchor="end"
|
|
height={70}
|
|
/>
|
|
<YAxis fontSize={12} tick={{ fill: '#6b7280' }} />
|
|
<Tooltip
|
|
contentStyle={{
|
|
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
|
border: '1px solid #ccc',
|
|
borderRadius: '8px',
|
|
}}
|
|
formatter={(value: number) => [`${value} karung`]}
|
|
labelFormatter={(label) => `Tanggal: ${label}`}
|
|
/>
|
|
<Legend />
|
|
{columnConfig.map((col) => (
|
|
<Bar
|
|
key={col.id}
|
|
dataKey={col.cameraName}
|
|
name={col.label}
|
|
fill={col.color}
|
|
barSize={8}
|
|
/>
|
|
))}
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default FeedTrendChart;
|