timing
This commit is contained in:
@@ -33,7 +33,7 @@ import { Card } from '@astryxdesign/core/Card';
|
||||
import { HStack } from '@astryxdesign/core/HStack';
|
||||
import { Text } from '@astryxdesign/core/Text';
|
||||
import { VStack } from '@astryxdesign/core/VStack';
|
||||
import { FileSpreadsheet, RefreshCw, UploadCloud } from 'lucide-react';
|
||||
import { FileSpreadsheet, UploadCloud } from 'lucide-react';
|
||||
import { errorMessage } from '@/api/client';
|
||||
import {
|
||||
fetchBatch,
|
||||
@@ -119,7 +119,6 @@ export function UploadsPanel({
|
||||
const [search, setSearch] = useState('');
|
||||
const from = range?.fromdate ?? '';
|
||||
const to = range?.todate ?? '';
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setError(null);
|
||||
@@ -151,7 +150,6 @@ export function UploadsPanel({
|
||||
*/
|
||||
const refreshLive = useCallback(
|
||||
async (rows: UploadReceipt[]) => {
|
||||
setIsRefreshing(true);
|
||||
const readings: Record<string, LiveReading> = {};
|
||||
for (const receipt of rows) {
|
||||
// Nothing further will arrive for these; the receipt is the answer.
|
||||
@@ -191,7 +189,6 @@ export function UploadsPanel({
|
||||
}
|
||||
}
|
||||
setLive((prev) => ({ ...prev, ...readings }));
|
||||
setIsRefreshing(false);
|
||||
},
|
||||
[],
|
||||
);
|
||||
@@ -200,6 +197,55 @@ export function UploadsPanel({
|
||||
if (receipts && receipts.length > 0) void refreshLive(receipts);
|
||||
}, [receipts, refreshLive]);
|
||||
|
||||
/** Receipts that could still change. A finished, shelved one never will. */
|
||||
const moving = useMemo(
|
||||
() => (receipts ?? []).filter((receipt) => !(receipt.laststatus === 'done' && receipt.shelvedat)),
|
||||
[receipts],
|
||||
);
|
||||
|
||||
/**
|
||||
* Keeps the moving rows current without anyone reloading the page.
|
||||
*
|
||||
* The list used to be read once, when the page loaded. Everything after that
|
||||
* — their admin releasing a drop, the run finishing, products reaching the
|
||||
* shelf — arrived only if the operator reloaded the page, which is exactly
|
||||
* what a status page exists to avoid. The "Check again" button that used to
|
||||
* paper over it is gone with the same change.
|
||||
*
|
||||
* Fifteen seconds, and only while something is unfinished: a page of forty
|
||||
* settled receipts makes no requests at all. It also pauses entirely while
|
||||
* the tab is in the background and takes a reading the moment it comes
|
||||
* forward, so a tab left open all afternoon costs nothing and is up to date
|
||||
* by the time it is looked at.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (moving.length === 0) return;
|
||||
|
||||
let stopped = false;
|
||||
let timer: ReturnType<typeof setTimeout>;
|
||||
|
||||
const read = () => {
|
||||
if (stopped || document.visibilityState !== 'visible') return;
|
||||
void refreshLive(moving);
|
||||
};
|
||||
const loop = () => {
|
||||
read();
|
||||
timer = setTimeout(loop, 15000);
|
||||
};
|
||||
timer = setTimeout(loop, 15000);
|
||||
|
||||
// Coming back to the tab is worth a reading straight away — that is the
|
||||
// moment somebody wants the answer.
|
||||
const onVisible = () => read();
|
||||
document.addEventListener('visibilitychange', onVisible);
|
||||
|
||||
return () => {
|
||||
stopped = true;
|
||||
clearTimeout(timer);
|
||||
document.removeEventListener('visibilitychange', onVisible);
|
||||
};
|
||||
}, [moving, refreshLive]);
|
||||
|
||||
const rows = useMemo(() => receipts ?? [], [receipts]);
|
||||
const showTenant = !tenantid;
|
||||
|
||||
@@ -312,15 +358,12 @@ export function UploadsPanel({
|
||||
aria-label="Search by file name"
|
||||
onChange={(event) => setSearch(event.target.value)}
|
||||
/>
|
||||
<Button
|
||||
label={isRefreshing ? 'Checking…' : 'Check again'}
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
isLoading={isRefreshing}
|
||||
isDisabled={isRefreshing}
|
||||
icon={<RefreshCw size={13} />}
|
||||
onClick={() => void refreshLive(rows)}
|
||||
/>
|
||||
{/* "Check again" stood here. It is gone because the page reads the
|
||||
moving rows by itself now — every fifteen seconds while something is
|
||||
unfinished, and again the moment the tab comes forward. A refresh
|
||||
button beside a list that refreshes itself is a button that never
|
||||
changes anything, and pressing it to find out whether it did is
|
||||
worse than not having it. */}
|
||||
{onUpload ? (
|
||||
<Button
|
||||
label="Upload spreadsheet"
|
||||
|
||||
Reference in New Issue
Block a user