first commit
This commit is contained in:
commit
b54624be96
226 files changed
+108840
No files matched your search
@@ -0,0 +1,103 @@
|
||||
import React from 'react';
|
||||
import type { ChickenWeight } from '../../types/api.ts';
|
||||
import { formatDateId, formatNumber } from '../../utils/format.ts';
|
||||
import { formatWeight, getTargetWeightForAge } from '../../utils/weight.ts';
|
||||
|
||||
interface DailyDetailPanelProps {
|
||||
row: ChickenWeight | null;
|
||||
docWeight: number;
|
||||
}
|
||||
|
||||
const DetailCard: React.FC<{
|
||||
label: string;
|
||||
value: string;
|
||||
icon: React.ReactNode;
|
||||
highlight?: boolean;
|
||||
}> = ({ label, value, icon, highlight = false }) => (
|
||||
<div
|
||||
className={`bg-white rounded-xl shadow-sm p-4 ${
|
||||
highlight ? 'border-2 border-red-500' : 'border border-gray-100'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="text-2xl text-red-500 flex-shrink-0">{icon}</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-xs text-gray-500">{label}</p>
|
||||
<p className="text-xl font-bold text-gray-800 truncate">{value}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const DailyDetailPanel: React.FC<DailyDetailPanelProps> = ({ row, docWeight }) => {
|
||||
if (!row) {
|
||||
return (
|
||||
<div className="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||
<div className="flex flex-col items-center justify-center py-6 text-center">
|
||||
<i className="fa-solid fa-calendar-xmark text-4xl text-gray-300 mb-3"></i>
|
||||
<p className="text-gray-500 font-medium">Belum ada data untuk tanggal ini</p>
|
||||
<p className="text-gray-400 text-sm mt-1">
|
||||
Pilih tanggal lain untuk melihat rincian harian
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const target = getTargetWeightForAge(row.age, docWeight);
|
||||
const deviation = target != null && row.average_weight > 0 ? row.average_weight - target : null;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4">
|
||||
<DetailCard
|
||||
label="Tanggal"
|
||||
value={formatDateId(row.date)}
|
||||
icon={<i className="fa-solid fa-calendar-day"></i>}
|
||||
/>
|
||||
<DetailCard
|
||||
label="Umur"
|
||||
value={`${row.age} hari`}
|
||||
icon={<i className="fa-solid fa-clock"></i>}
|
||||
/>
|
||||
<DetailCard
|
||||
label="DOC"
|
||||
value={formatWeight(row.doc_weight, { decimals: 0 })}
|
||||
icon={<i className="fa-solid fa-egg"></i>}
|
||||
/>
|
||||
<DetailCard
|
||||
label="AVG Berat"
|
||||
value={formatWeight(row.average_weight, { stripTrailingZeros: true })}
|
||||
icon={<i className="fa-solid fa-weight-scale"></i>}
|
||||
highlight
|
||||
/>
|
||||
<DetailCard
|
||||
label="Uniformity"
|
||||
value={`${formatNumber(row.uniformity, 2, 2, true)}%`}
|
||||
icon={<i className="fa-solid fa-percent"></i>}
|
||||
/>
|
||||
<DetailCard
|
||||
label="ADG"
|
||||
value={`${formatNumber(row.average_daily_gain, 2, 2, true)} g/hari`}
|
||||
icon={<i className="fa-solid fa-chart-line"></i>}
|
||||
/>
|
||||
<DetailCard
|
||||
label="Populasi"
|
||||
value={`${formatNumber(row.chicken_count, 0)} ekor`}
|
||||
icon={<i className="fa-solid fa-users"></i>}
|
||||
/>
|
||||
{deviation != null && (
|
||||
<DetailCard
|
||||
label="Deviasi vs Target"
|
||||
value={`${deviation >= 0 ? '+' : ''}${formatWeight(Math.abs(deviation), {
|
||||
stripTrailingZeros: true,
|
||||
})}`}
|
||||
icon={<i className="fa-solid fa-arrow-trend-up"></i>}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DailyDetailPanel;
|
||||
Reference in new issue
Block a user