import React, { useMemo } from 'react';
import {
FeedSackLogEntry,
ManualFeedSackEntry,
FeedSackColumnConfig,
} from '../../types/counting.ts';
import { useAppContext } from '../../context/AppContext.tsx';
import { formatNumber } from '../../utils/formatters.ts';
import { getEffectiveDate } from '../../utils/dateFilter.ts';
const StatItem: React.FC<{
icon: React.ReactNode;
label: string;
manualValue: string;
iotValue: string;
colorOverride?: string;
}> = ({ icon, label, manualValue, iotValue, colorOverride }) => (
{/* Manual */}
{/* IOT */}
);
interface FeedStatsProps {
data: FeedSackLogEntry[];
manualEntries: ManualFeedSackEntry[];
columnConfig: FeedSackColumnConfig[];
effectiveDate?: Date;
}
const FeedStats: React.FC = ({
data,
manualEntries,
columnConfig,
effectiveDate,
}) => {
const { cycleData } = useAppContext();
const displayDate = effectiveDate ?? getEffectiveDate();
const todayLabel = useMemo(() => {
return new Intl.DateTimeFormat('id-ID', {
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: 'Asia/Jakarta',
}).format(displayDate);
}, [displayDate]);
const totalCycleLabel = useMemo(() => {
const startDate = cycleData.startDate.toLocaleDateString('id-ID', {
day: 'numeric',
month: 'short',
});
const endDate = displayDate.toLocaleDateString('id-ID', {
day: 'numeric',
month: 'short',
});
return `Total (${startDate} - ${endDate})`;
}, [cycleData.startDate, displayDate]);
const columnStats = useMemo(() => {
return columnConfig.map((col) => {
const cameraIotData = data.filter((log) => log.cameraName === col.cameraName);
const cameraManualData = manualEntries.filter((entry) => entry.cameraName === col.cameraName);
const calculateIotCount = (dataSet: FeedSackLogEntry[], days: number | 'cycle') => {
let startDate: Date;
if (days === 'cycle') {
startDate = new Date(cycleData.startDate);
} else {
startDate = new Date(displayDate);
startDate.setDate(displayDate.getDate() - (days - 1));
}
startDate.setHours(0, 0, 0, 0);
return dataSet
.filter((log) => log.timestamp >= startDate)
.reduce((sum, log) => sum + log.count, 0);
};
const calculateManualCount = (dataSet: ManualFeedSackEntry[], days: number | 'cycle') => {
let startDate: Date;
if (days === 'cycle') {
startDate = new Date(cycleData.startDate);
} else {
startDate = new Date(displayDate);
startDate.setDate(displayDate.getDate() - (days - 1));
}
startDate.setHours(0, 0, 0, 0);
return dataSet
.filter((entry) => {
const entryDate = new Date(entry.date);
return !isNaN(entryDate.getTime()) && entryDate >= startDate;
})
.reduce((sum, entry) => sum + entry.count, 0);
};
return {
...col,
todayManual: calculateManualCount(cameraManualData, 1),
todayIot: calculateIotCount(cameraIotData, 1),
weekManual: calculateManualCount(cameraManualData, 'cycle'),
weekIot: calculateIotCount(cameraIotData, 'cycle'),
};
});
}, [data, manualEntries, columnConfig, cycleData, displayDate]);
const gridCols =
columnStats.length <= 2
? 'md:grid-cols-2'
: columnStats.length <= 3
? 'md:grid-cols-3'
: 'md:grid-cols-2 lg:grid-cols-4';
return (
{columnStats.map((stat) => (
{stat.label}
{stat.cameraName}
}
label={todayLabel}
manualValue={formatNumber(stat.todayManual)}
iotValue={formatNumber(stat.todayIot)}
colorOverride={stat.color}
/>
}
label={totalCycleLabel}
manualValue={formatNumber(stat.weekManual)}
iotValue={formatNumber(stat.weekIot)}
colorOverride={stat.color}
/>
))}
);
};
export default FeedStats;