timing
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Badge } from '@astryxdesign/core/Badge';
|
||||
import { Button } from '@astryxdesign/core/Button';
|
||||
import { Card } from '@astryxdesign/core/Card';
|
||||
@@ -118,6 +118,41 @@ export function SheetImportPanel({ tenantid, locationid }: SheetImportPanelProps
|
||||
*/
|
||||
const [dropId, setDropId] = useState<string | null>(null);
|
||||
const [isWorking, setIsWorking] = useState(false);
|
||||
/**
|
||||
* The live watch on the current batch.
|
||||
*
|
||||
* Held so it can be called off — when a new file replaces this one, when the
|
||||
* panel resets, and when the drawer closes. Without that, closing the drawer
|
||||
* mid-run left a poll reading a batch nothing was rendering.
|
||||
*/
|
||||
const watcher = useRef<AbortController | null>(null);
|
||||
|
||||
useEffect(() => () => watcher.current?.abort(), []);
|
||||
|
||||
/**
|
||||
* Follows a batch until it finishes, updating the steps as it goes.
|
||||
*
|
||||
* NOT awaited by the caller, and that is the point. The upload is over once
|
||||
* the service has the file; what follows is a wait — often on their admin to
|
||||
* release the drop — and holding the submit handler open for it would keep
|
||||
* the button spinning for hours. Every reading lands through `setBatch`, so
|
||||
* the panel re-renders on each one.
|
||||
*/
|
||||
function watch(batchId: string) {
|
||||
watcher.current?.abort();
|
||||
const controller = new AbortController();
|
||||
watcher.current = controller;
|
||||
void pollBatch(batchId, setBatch, controller.signal)
|
||||
.then((settled) => {
|
||||
if (!controller.signal.aborted) setBatch(settled);
|
||||
})
|
||||
.catch(() => {
|
||||
/* Aborted, or the service stopped answering. The last reading stays on
|
||||
screen with its batch id, which is what the operator comes back
|
||||
with — inventing an error over a poll that was cancelled would
|
||||
report a failure that did not happen. */
|
||||
});
|
||||
}
|
||||
/** Set when the upload succeeded but its receipt could not be filed. */
|
||||
const [receiptError, setReceiptError] = useState<string | null>(null);
|
||||
|
||||
@@ -143,6 +178,8 @@ export function SheetImportPanel({ tenantid, locationid }: SheetImportPanelProps
|
||||
setFile(chosen);
|
||||
setParsed(null);
|
||||
setParseError(null);
|
||||
// A new file is a new upload, so stop watching the old one first.
|
||||
watcher.current?.abort();
|
||||
setBatch(null);
|
||||
setDropId(null);
|
||||
setReceiptError(null);
|
||||
@@ -234,7 +271,8 @@ export function SheetImportPanel({ tenantid, locationid }: SheetImportPanelProps
|
||||
}
|
||||
}
|
||||
|
||||
setBatch(await pollBatch(submitted.batch_id, setBatch));
|
||||
// The steps from here on arrive by themselves — see `watch`.
|
||||
watch(submitted.batch_id);
|
||||
} catch (cause) {
|
||||
setParseError(errorMessage(cause));
|
||||
} finally {
|
||||
@@ -695,6 +733,7 @@ export function SheetImportPanel({ tenantid, locationid }: SheetImportPanelProps
|
||||
label="Send another file"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
watcher.current?.abort();
|
||||
setBatch(null);
|
||||
setParsed(null);
|
||||
setFile(null);
|
||||
|
||||
Reference in New Issue
Block a user