update karung related component to follow cutoff time
This commit is contained in:
1 parent
26c69b340d
commit
03c7dcb646
5 files changed
+84
-53
No files matched your search
+47
-32
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { api, ApiError, errorMessage } from '../services/apiClient.ts';
|
||||
import { api, errorMessage } from '../services/apiClient.ts';
|
||||
import type {
|
||||
ChickenCounting,
|
||||
ChickenWeight,
|
||||
@@ -52,7 +52,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
const [countings, setCountings] = useState<ChickenCounting[]>([]);
|
||||
const [manualInputs, setManualInputs] = useState<ManualInput[]>([]);
|
||||
const [weights, setWeights] = useState<ChickenWeight[]>([]);
|
||||
const [karung, setKarung] = useState<Karung | null>(null);
|
||||
const [karungs, setKarungs] = useState<Karung[]>([]);
|
||||
const [iotDayAggregates, setIotDayAggregates] = useState<EndCycleIotDayAggregate[]>([]);
|
||||
const [reportOpen, setReportOpen] = useState(false);
|
||||
const [reportType, setReportType] = useState<DashboardReportType>('daily');
|
||||
@@ -64,7 +64,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
setCountings([]);
|
||||
setManualInputs([]);
|
||||
setWeights([]);
|
||||
setKarung(null);
|
||||
setKarungs([]);
|
||||
setIotDayAggregates([]);
|
||||
return;
|
||||
}
|
||||
@@ -78,19 +78,15 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
api.countings.sync({ cycle_id: cycleId }).catch(() => null),
|
||||
api.weights.sync({ cycle_id: cycleId }).catch(() => null),
|
||||
]);
|
||||
const [kpiRows, countingRows, manualRows, weightRows, freshCycle] = await Promise.all([
|
||||
api.kpis.list({ cycle_id: cycleId }),
|
||||
api.countings.list({ cycle_id: cycleId }),
|
||||
api.manualInputs.list({ cycle_id: cycleId }),
|
||||
api.weights.list({ cycle_id: cycleId }),
|
||||
api.cycles?.retrieve?.(cycleId)?.catch(() => null) ?? Promise.resolve(null),
|
||||
]);
|
||||
let latestKarung: Karung | null = null;
|
||||
try {
|
||||
latestKarung = await api.karungs.latest({ cycle_id: cycleId });
|
||||
} catch (err) {
|
||||
if (!(err instanceof ApiError && err.status === 404)) throw err;
|
||||
}
|
||||
const [kpiRows, countingRows, manualRows, weightRows, karungRows, freshCycle] =
|
||||
await Promise.all([
|
||||
api.kpis.list({ cycle_id: cycleId }),
|
||||
api.countings.list({ cycle_id: cycleId }),
|
||||
api.manualInputs.list({ cycle_id: cycleId }),
|
||||
api.weights.list({ cycle_id: cycleId }),
|
||||
api.karungs.list({ cycle_id: cycleId }).catch(() => []),
|
||||
api.cycles?.retrieve?.(cycleId)?.catch(() => null) ?? Promise.resolve(null),
|
||||
]);
|
||||
if (freshCycle) {
|
||||
updateCycle(cycleId, freshCycle);
|
||||
}
|
||||
@@ -98,7 +94,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
setCountings(countingRows);
|
||||
setManualInputs(manualRows);
|
||||
setWeights(weightRows);
|
||||
setKarung(latestKarung);
|
||||
setKarungs(karungRows);
|
||||
|
||||
// Best-effort IoT aggregates for end-cycle root cause (non-blocking on failure).
|
||||
try {
|
||||
@@ -180,10 +176,23 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
void reload();
|
||||
}, [fetchDashboardData, reload]);
|
||||
|
||||
const visibleThrough = selectedCycle?.visible_through_date;
|
||||
const visibleKpis = useMemo(
|
||||
() => throughVisibleDate(kpis, visibleThrough),
|
||||
[kpis, visibleThrough]
|
||||
);
|
||||
const sortedKarungs = useMemo(
|
||||
() => [...karungs].sort((a, b) => a.date.localeCompare(b.date)),
|
||||
[karungs]
|
||||
);
|
||||
const visibleKarungs = useMemo(
|
||||
() => throughVisibleDate(sortedKarungs, visibleThrough),
|
||||
[sortedKarungs, visibleThrough]
|
||||
);
|
||||
const latestKarung = visibleKarungs[visibleKarungs.length - 1] ?? null;
|
||||
|
||||
const cards: KpiCardModel[] = useMemo(() => {
|
||||
// All cards share the latest complete KPI day (not calendar current_day / live IoT).
|
||||
const visibleThrough = selectedCycle?.visible_through_date;
|
||||
const visibleKpis = throughVisibleDate(kpis, visibleThrough);
|
||||
const latest = visibleKpis[0] ?? null;
|
||||
const anchorDate = latest?.date ?? null;
|
||||
|
||||
@@ -285,7 +294,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
targetView: 'eefDashboard',
|
||||
},
|
||||
];
|
||||
}, [kpis, weights, selectedCycle]);
|
||||
}, [visibleKpis, weights, selectedCycle, visibleThrough]);
|
||||
|
||||
const countingAccuracyWarning = useMemo(() => {
|
||||
if (!selectedCycle) return null;
|
||||
@@ -299,8 +308,6 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
|
||||
const insightContext = useMemo(() => {
|
||||
if (selectedKandangId == null) return null;
|
||||
const visibleThrough = selectedCycle?.visible_through_date;
|
||||
const visibleKpis = throughVisibleDate(kpis, visibleThrough);
|
||||
const latest = visibleKpis[0] ?? null;
|
||||
const anchorDate = latest?.date ?? null;
|
||||
const weightsThroughAnchor = anchorDate
|
||||
@@ -330,8 +337,10 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
? null
|
||||
: Math.round((100 - latest.chicken_life_percentage) * 100) / 100,
|
||||
karung_dituang_hari_ini:
|
||||
latest != null ? latest.feed : (karung?.feed_use_today ?? karung?.out_today ?? null),
|
||||
pakan_kumulatif_karung: karung?.feed_use_total ?? latest?.feed_total ?? null,
|
||||
latest != null
|
||||
? latest.feed
|
||||
: (latestKarung?.feed_use_today ?? latestKarung?.out_today ?? null),
|
||||
pakan_kumulatif_karung: latestKarung?.feed_use_total ?? latest?.feed_total ?? null,
|
||||
ayam_hidup_ekor:
|
||||
latest != null ? Math.max(0, latest.chicken_life - (latest.harvest_total ?? 0)) : null,
|
||||
persen_hidup: latest?.chicken_life_percentage ?? null,
|
||||
@@ -343,12 +352,18 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
latest?.harvest_weight_total != null ? latest.harvest_weight_total / 1000 : null,
|
||||
uniformity_persen: weightOnAnchor?.uniformity ?? null,
|
||||
});
|
||||
}, [selectedKandangId, selectedKandang, selectedCycle, kpis, weights, karung]);
|
||||
}, [
|
||||
selectedKandangId,
|
||||
selectedKandang,
|
||||
selectedCycle,
|
||||
visibleKpis,
|
||||
weights,
|
||||
visibleThrough,
|
||||
latestKarung,
|
||||
]);
|
||||
|
||||
const insightMetrics = useMemo(() => {
|
||||
if (selectedKandangId == null) return null;
|
||||
const visibleThrough = selectedCycle?.visible_through_date;
|
||||
const visibleKpis = throughVisibleDate(kpis, visibleThrough);
|
||||
const latest = visibleKpis[0] ?? null;
|
||||
const anchorDate = latest?.date ?? null;
|
||||
const weightsThroughAnchor = anchorDate
|
||||
@@ -360,17 +375,17 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
|
||||
weights: weightsThroughAnchor,
|
||||
currentDay: latest?.age ?? selectedCycle?.current_day ?? null,
|
||||
docInCount: selectedCycle?.doc_in_count ?? null,
|
||||
pakanKumulatifFallback: karung?.feed_use_total ?? latest?.feed_total ?? null,
|
||||
pakanKumulatifFallback: latestKarung?.feed_use_total ?? latest?.feed_total ?? null,
|
||||
});
|
||||
}, [selectedKandangId, selectedCycle, kpis, weights, karung]);
|
||||
}, [selectedKandangId, selectedCycle, visibleKpis, weights, visibleThrough, latestKarung]);
|
||||
|
||||
if (!selectedCycle) return <EmptyFarm onSettings={() => setView('kandangSettings')} />;
|
||||
|
||||
const feedTotal = karung?.feed_use_total ?? kpis[0]?.feed_total ?? 0;
|
||||
const feedTotal = latestKarung?.feed_use_total ?? visibleKpis[0]?.feed_total ?? 0;
|
||||
const feedWeightKg = feedTotal * 50;
|
||||
const feedInitialBalance = selectedCycle?.feed_initial_balance ?? 0;
|
||||
const feedInTotal = (karung?.in_total ?? 0) + feedInitialBalance;
|
||||
const feedOutTotal = karung?.out_total ?? 0;
|
||||
const feedInTotal = (latestKarung?.in_total ?? 0) + feedInitialBalance;
|
||||
const feedOutTotal = latestKarung?.out_total ?? 0;
|
||||
const feedSaldo = feedInTotal - feedTotal - feedOutTotal;
|
||||
const feedSaldoColor =
|
||||
feedSaldo > 0 ? 'text-green-600' : feedSaldo < 0 ? 'text-red-600' : 'text-gray-600';
|
||||
|
||||
Reference in new issue
Block a user