first commit
This commit is contained in:
commit
367533c02b
171 files changed
+101175
No files matched your search
@@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import type { LatestAvg } from '../../types/api.ts';
|
||||
import { formatDateId, formatNumber } from '../../utils/format.ts';
|
||||
import {
|
||||
adgStatus,
|
||||
formatWeight,
|
||||
getTargetWeightForAge,
|
||||
type WeightStatus,
|
||||
uniformityStatus,
|
||||
weightDeviationStatus,
|
||||
} from '../../utils/weight.ts';
|
||||
|
||||
const statusText: Record<WeightStatus, string> = {
|
||||
ok: 'text-green-600',
|
||||
warning: 'text-yellow-600',
|
||||
critical: 'text-red-600',
|
||||
};
|
||||
|
||||
const StatItem: React.FC<{
|
||||
icon: React.ReactNode;
|
||||
label: string;
|
||||
value: string;
|
||||
status: WeightStatus;
|
||||
}> = ({ icon, label, value, status }) => (
|
||||
<div className="flex items-center p-2 rounded-lg hover:bg-gray-50">
|
||||
<div className="text-2xl text-gray-400 w-12">{icon}</div>
|
||||
<div>
|
||||
<p className="text-sm text-gray-600 font-medium">{label}</p>
|
||||
<p className={`text-2xl font-bold ${statusText[status]}`}>
|
||||
<span className="text-base font-medium">{value}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
interface WeightStatsProps {
|
||||
latest: LatestAvg | null;
|
||||
totalDays: number;
|
||||
}
|
||||
|
||||
const WeightStats: React.FC<WeightStatsProps> = ({ latest, totalDays }) => {
|
||||
const target = latest ? getTargetWeightForAge(latest.age, totalDays) : null;
|
||||
|
||||
return (
|
||||
<div className="bg-white p-6 rounded-xl shadow-sm h-full">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-xl font-bold">Statistik Utama Pertumbuhan</h2>
|
||||
{latest?.date ? (
|
||||
<p className="text-sm text-gray-500 mt-1">Data per: {formatDateId(latest.date)}</p>
|
||||
) : null}
|
||||
</div>
|
||||
{!latest ? (
|
||||
<div className="flex flex-col items-center justify-center h-48 text-center">
|
||||
<i className="fa-solid fa-exclamation-triangle text-5xl text-yellow-500 mb-4"></i>
|
||||
<h3 className="text-lg font-semibold text-gray-700 mb-2">Data Tidak Tersedia</h3>
|
||||
<p className="text-sm text-gray-500 max-w-xs">
|
||||
Belum ada data timbangan untuk siklus ini. Data akan muncul setelah ayam ditimbang.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<StatItem
|
||||
icon={<i className="fa-solid fa-weight-scale"></i>}
|
||||
label="Rata-rata Berat Ayam"
|
||||
value={formatWeight(latest.average_weight, { stripTrailingZeros: true })}
|
||||
status={weightDeviationStatus(latest.average_weight, target)}
|
||||
/>
|
||||
<StatItem
|
||||
icon={<i className="fa-solid fa-chart-line"></i>}
|
||||
label="Pertambahan Bobot Harian (ADG)"
|
||||
value={formatWeight(latest.average_daily_gain, {
|
||||
suffix: '/hari',
|
||||
decimals: 2,
|
||||
truncate: true,
|
||||
})}
|
||||
status={adgStatus(latest.average_daily_gain)}
|
||||
/>
|
||||
<StatItem
|
||||
icon={<i className="fa-solid fa-percent"></i>}
|
||||
label="Tingkat Keseragaman (Uniformity)"
|
||||
value={`${formatNumber(latest.uniformity, 2, 2, true)} %`}
|
||||
status={uniformityStatus(latest.uniformity)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WeightStats;
|
||||
Reference in new issue
Block a user