Files
dashboard-cpsp/components/feedSack/FeedStats.tsx
T

146 lines
4.8 KiB
TypeScript

import React, { useMemo } from 'react';
import type { Karung, ManualInput } from '../../types/api.ts';
import { formatNumber } from '../../utils/format.ts';
const StatItem: React.FC<{
icon: React.ReactNode;
label: string;
value: number | null;
colorOverride?: string;
}> = ({ icon, label, value, colorOverride }) => (
<div className="border border-gray-200 rounded-lg p-3 hover:border-gray-300 transition-colors">
<div className="flex items-start gap-2 mb-3 min-w-0">
<div className="mt-0.5 shrink-0 text-gray-500">{icon}</div>
<p className="min-w-0 text-[11px] sm:text-xs font-medium leading-tight text-gray-700 break-words">
{label}
</p>
</div>
<div className="rounded-md bg-gray-50/70 p-3">
<p
className="text-xl sm:text-2xl font-bold leading-none"
style={{ color: colorOverride ?? '#374151' }}
>
{value == null ? formatNumber(0) : formatNumber(value)}
</p>
<p className="text-xs text-gray-400 mt-0.5">karung</p>
</div>
</div>
);
interface FeedStatsProps {
latest: Karung | null;
latestManual: ManualInput | null;
cycleStartDate: string;
displayDate: string;
}
const FeedStats: React.FC<FeedStatsProps> = ({
latest,
latestManual,
cycleStartDate,
displayDate,
}) => {
const formatDisplayDate = (iso: string) =>
new Intl.DateTimeFormat('id-ID', {
day: 'numeric',
month: 'long',
year: 'numeric',
}).format(new Date(`${iso}T00:00:00`));
const todayLabel = useMemo(() => formatDisplayDate(displayDate), [displayDate]);
const totalCycleLabel = useMemo(() => {
const start = new Intl.DateTimeFormat('id-ID', {
day: 'numeric',
month: 'short',
}).format(new Date(`${cycleStartDate}T00:00:00`));
const end = new Intl.DateTimeFormat('id-ID', {
day: 'numeric',
month: 'short',
}).format(new Date(`${displayDate}T00:00:00`));
return `Total (${start} - ${end})`;
}, [cycleStartDate, displayDate]);
const columns = useMemo(
() => [
{
key: 'masuk',
title: 'Karung Masuk',
color: '#2563eb',
icon: <i className="fa-solid fa-arrow-down text-blue-600"></i>,
iotToday: latest?.in_today ?? 0,
iotTotal: latest?.in_total ?? 0,
manualToday: latestManual?.feed_in_manual ?? 0,
manualTotal: latestManual?.feed_in_manual_total ?? 0,
},
{
key: 'dituang',
title: 'Karung Dituang',
color: '#ea580c',
icon: <i className="fa-solid fa-arrow-up text-orange-600"></i>,
iotToday: latest?.feed_use_today ?? 0,
iotTotal: latest?.feed_use_total ?? 0,
manualToday: latestManual?.feed_use_manual ?? 0,
manualTotal: latestManual?.feed_use_manual_total ?? 0,
},
{
key: 'keluar',
title: 'Karung Keluar',
color: '#dc2626',
icon: <i className="fa-solid fa-arrow-right text-red-600"></i>,
iotToday: latest?.out_today ?? 0,
iotTotal: latest?.out_total ?? 0,
manualToday: latestManual?.feed_out_manual ?? 0,
manualTotal: latestManual?.feed_out_manual_total ?? 0,
},
],
[latest, latestManual]
);
return (
<div className="bg-white p-4 sm:p-6 rounded-xl shadow-sm">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 sm:gap-6">
{columns.map((col) => (
<div key={col.key}>
<h3 className="font-semibold text-sm sm:text-base mb-2" style={{ color: col.color }}>
{col.title}
</h3>
<div className="grid grid-cols-2 gap-3">
<div className="space-y-3">
<StatItem
icon={<i className="fa-solid fa-microchip text-purple-600"></i>}
label={`IOT · ${todayLabel}`}
value={col.iotToday}
colorOverride={col.color}
/>
<StatItem
icon={<i className="fa-solid fa-microchip text-purple-600"></i>}
label={`IOT · ${totalCycleLabel}`}
value={col.iotTotal}
colorOverride={col.color}
/>
</div>
<div className="space-y-3">
<StatItem
icon={<i className="fa-solid fa-user-pen text-gray-500"></i>}
label={`Manual · ${todayLabel}`}
value={col.manualToday}
colorOverride="#6b7280"
/>
<StatItem
icon={<i className="fa-solid fa-user-pen text-gray-500"></i>}
label={`Manual · ${totalCycleLabel}`}
value={col.manualTotal}
colorOverride="#6b7280"
/>
</div>
</div>
</div>
))}
</div>
</div>
);
};
export default FeedStats;