update kpi report to include summary for daily report and end cycle
This commit is contained in:
1 parent
6c21af745d
commit
4439e3b7b1
5 files changed
+454
-43
No files matched your search
@@ -17,11 +17,8 @@ import {
|
||||
formatNumber,
|
||||
formatRatio,
|
||||
} from '../../utils/format.ts';
|
||||
import type {
|
||||
DashboardReportFcrRow,
|
||||
DashboardReportPayload,
|
||||
DashboardReportType,
|
||||
} from '../../types/dashboardReport.ts';
|
||||
import { buildReportSummary, formatSummaryValue } from '../../utils/reportSummary.ts';
|
||||
import type { DashboardReportPayload, DashboardReportType } from '../../types/dashboardReport.ts';
|
||||
import { Banner } from '../ui/Feedback.tsx';
|
||||
|
||||
type Props = {
|
||||
@@ -55,17 +52,6 @@ const harvestKgCell = (grams: number | null | undefined): string => {
|
||||
return `${formatNumber(Number(grams) / 1000, 1)} kg`;
|
||||
};
|
||||
|
||||
const latestValidRatio = (
|
||||
rows: Array<DashboardReportFcrRow | { iotEef: number | null }>,
|
||||
key: 'iotFcr' | 'iotEef'
|
||||
): number | null => {
|
||||
for (let i = rows.length - 1; i >= 0; i -= 1) {
|
||||
const value = (rows[i] as Record<string, number | null>)[key];
|
||||
if (value != null && Number.isFinite(value)) return value;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const ReportPreviewOverlay: React.FC<Props> = ({ open, reportType, onClose }) => {
|
||||
const { selectedCycle, selectedKandang, selectedSite } = useFarm();
|
||||
const isEndCycle = reportType === 'end_cycle';
|
||||
@@ -138,6 +124,11 @@ const ReportPreviewOverlay: React.FC<Props> = ({ open, reportType, onClose }) =>
|
||||
await exportElementToPdf(printRef.current, filename);
|
||||
}, [payload, isEndCycle]);
|
||||
|
||||
const summary = useMemo(
|
||||
() => (payload ? buildReportSummary(payload) : null),
|
||||
[payload]
|
||||
);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
const title = isEndCycle ? 'Laporan Akhir Siklus' : 'Laporan Harian';
|
||||
@@ -151,7 +142,7 @@ const ReportPreviewOverlay: React.FC<Props> = ({ open, reportType, onClose }) =>
|
||||
const endDateLabel = selectedCycle ? formatDateId(selectedCycle.start_date) : '';
|
||||
const dataDates =
|
||||
selectedCycle && payload
|
||||
? `${endDateLabel} – ${formatDateId(payload.counting[payload.counting.length - 1]?.date ?? selectedCycle.start_date)}`
|
||||
? `(${endDateLabel} - ${formatDateId(payload.counting[payload.counting.length - 1]?.date ?? selectedCycle.start_date)})`
|
||||
: '';
|
||||
const cycleRange = selectedCycle
|
||||
? formatDateRange(selectedCycle.start_date, selectedCycle.end_date)
|
||||
@@ -263,14 +254,62 @@ const ReportPreviewOverlay: React.FC<Props> = ({ open, reportType, onClose }) =>
|
||||
<div style={{ fontSize: 12, color: '#6b7280', marginTop: 2 }}>
|
||||
Dicetak: {printedDate}
|
||||
</div>
|
||||
{isEndCycle && (
|
||||
<div style={{ fontSize: 22, color: '#111827', marginTop: 12, fontWeight: 700 }}>
|
||||
FCR akhir: {ratioCell(latestValidRatio(payload.fcr, 'iotFcr'))} · EEF akhir:{' '}
|
||||
{ratioCell(latestValidRatio(payload.eef, 'iotEef'))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{summary && (
|
||||
<div
|
||||
data-pdf-block
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(4, minmax(0, 1fr))',
|
||||
gap: 8,
|
||||
marginBottom: 24,
|
||||
}}
|
||||
>
|
||||
{summary.metrics.map((metric) => {
|
||||
const formattedValue = formatSummaryValue(metric);
|
||||
return (
|
||||
<div
|
||||
key={metric.key}
|
||||
style={{
|
||||
border: '1px solid #e9d5ff',
|
||||
borderTop: '3px solid #7e22ce',
|
||||
borderRadius: 8,
|
||||
padding: '8px 10px',
|
||||
background: '#faf5ff',
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: 10, color: '#6b7280', fontWeight: 600 }}>
|
||||
{metric.label}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: '#111827',
|
||||
fontWeight: 700,
|
||||
marginTop: 2,
|
||||
}}
|
||||
>
|
||||
{formattedValue}
|
||||
{metric.unit && formattedValue !== '—' ? (
|
||||
<span
|
||||
style={{
|
||||
fontSize: 10,
|
||||
fontWeight: 500,
|
||||
color: '#6b7280',
|
||||
marginLeft: 4,
|
||||
}}
|
||||
>
|
||||
{metric.unit}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ReportTable title="Hitung Ayam harian">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
Reference in new issue
Block a user