update all page to refresh immidiately without clicking sync button or refreshing the whole page

This commit is contained in:
Alberto-Audrix committed 2026-10-07 11:17:44 +07:00
1 parent d5b0c12c40
commit 83a41fbbcb
15 files changed
+490 -151

No files matched your search

+56 -28
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { api, ApiError, errorMessage } from '../services/apiClient.ts';
import type { ChickenWeight, LatestAvg } from '../types/api.ts';
import { useFarm } from '../context/FarmContext.tsx';
@@ -18,7 +18,7 @@ import DailyDetailPanel from './weight/DailyDetailPanel.tsx';
import { PageAiInsight } from './shared/PageAiInsight.tsx';
const WeightMonitoringPage: React.FC<{ onSettings: () => void }> = ({ onSettings }) => {
const { selectedCycle, selectedSite, selectedKandang } = useFarm();
const { selectedCycle, selectedSite, selectedKandang, updateCycle } = useFarm();
const [rows, setRows] = useState<ChickenWeight[]>([]);
const [latest, setLatest] = useState<LatestAvg | null>(null);
const [loading, setLoading] = useState(false);
@@ -29,21 +29,39 @@ const WeightMonitoringPage: React.FC<{ onSettings: () => void }> = ({ onSettings
const isClosedCycle = !selectedCycle || resolveCycleStatus(selectedCycle) !== 'active';
const reload = async (cycleId: number) => {
setError(null);
try {
const list = await api.weights.list({ cycle_id: cycleId });
setRows(list);
try {
setLatest(await api.weights.latestAvg({ cycle_id: cycleId }));
} catch (err) {
if (err instanceof ApiError && err.status === 404) setLatest(null);
else throw err;
const reload = useCallback(
async (cycleId: number, isBackground = false) => {
if (!isBackground) {
setLoading(true);
}
} catch (err) {
setError(errorMessage(err));
}
};
setError(null);
try {
const [list, freshCycle] = await Promise.all([
api.weights.list({ cycle_id: cycleId }),
api.cycles?.retrieve?.(cycleId)?.catch(() => null) ?? Promise.resolve(null),
]);
if (freshCycle) {
updateCycle(cycleId, freshCycle);
}
setRows(list);
try {
setLatest(await api.weights.latestAvg({ cycle_id: cycleId }));
} catch (err) {
if (err instanceof ApiError && err.status === 404) setLatest(null);
else throw err;
}
} catch (err) {
if (!isBackground) {
setError(errorMessage(err));
}
} finally {
if (!isBackground) {
setLoading(false);
}
}
},
[updateCycle]
);
useEffect(() => {
if (!selectedCycle) {
@@ -52,20 +70,30 @@ const WeightMonitoringPage: React.FC<{ onSettings: () => void }> = ({ onSettings
setSelectedDate('');
return;
}
let cancelled = false;
(async () => {
setLoading(true);
try {
await reload(selectedCycle.id);
} finally {
if (!cancelled) setLoading(false);
const cycleId = selectedCycle.id;
void reload(cycleId, false);
const interval = setInterval(() => {
if (document.visibilityState === 'visible') {
void reload(cycleId, true);
}
}, 60000);
const handleFocusOrVisibility = () => {
if (document.visibilityState === 'visible') {
void reload(cycleId, true);
}
})();
return () => {
cancelled = true;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedCycle]);
document.addEventListener('visibilitychange', handleFocusOrVisibility);
window.addEventListener('focus', handleFocusOrVisibility);
return () => {
clearInterval(interval);
document.removeEventListener('visibilitychange', handleFocusOrVisibility);
window.removeEventListener('focus', handleFocusOrVisibility);
};
}, [selectedCycle?.id, reload]);
// Days without a weighing are stored as 0 g. Charts skip those days so the
// line does not drop to zero at the end of a cycle, mirroring the old