first commit

This commit is contained in:
Alberto-Audrix committed 2026-08-26 13:46:05 +07:00
commit 367533c02b
171 files changed
+101175

No files matched your search

+90
View File
@@ -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;