mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 04:33:11 +00:00
fix(sites): hold Delete until the reopened dialog's open work-order recheck lands
The open work-order query keeps its cached result between dialog opens, so on reopen the background refetch ran while isLoading was false and Delete was enabled with the previous count. A work order created at the site since the last open could be deleted past without a warning. Treat an in-flight fetch as an unknown count: Delete and View open work orders wait, the stale copy is hidden and the checking spinner shows until the fresh count arrives.
This commit is contained in:
parent
2281c7c82d
commit
7bde8aacf2
2 changed files with 43 additions and 4 deletions
|
|
@ -51,8 +51,9 @@ export function SiteDeleteDialog({
|
|||
refetch,
|
||||
} = useSiteOpenWorkOrders(siteId, open);
|
||||
const openCount = openWorkOrders?.count ?? 0;
|
||||
// Without the count the warning cannot be shown, so Delete waits for a successful check.
|
||||
const countUnknown = isLoading || isError;
|
||||
// Without a current count the warning cannot be trusted, so Delete waits for a successful check.
|
||||
// `isFetching` covers reopening: the count cached from the last open is stale until the refetch lands.
|
||||
const countUnknown = isLoading || isFetching || isError;
|
||||
// The server caps the id list; when it doesn't cover the stated count, open the site's whole board.
|
||||
const openIds = openWorkOrders?.workOrderIds ?? [];
|
||||
const openWorkOrdersHref =
|
||||
|
|
@ -73,7 +74,9 @@ export function SiteDeleteDialog({
|
|||
>
|
||||
<DialogTitle id="site-delete-title">Delete this site?</DialogTitle>
|
||||
<DialogContent>
|
||||
{isLoading && <CircularProgress size={20} aria-label="Checking open work orders" />}
|
||||
{isFetching && !isError && (
|
||||
<CircularProgress size={20} aria-label="Checking open work orders" />
|
||||
)}
|
||||
{isError && <DialogContentText role="alert">{CHECK_FAILED_MESSAGE}</DialogContentText>}
|
||||
{!countUnknown && (
|
||||
<DialogContentText>{describeDeletion(siteCode, openCount)}</DialogContentText>
|
||||
|
|
@ -88,7 +91,7 @@ export function SiteDeleteDialog({
|
|||
Try again
|
||||
</Button>
|
||||
)}
|
||||
{openCount > 0 && (
|
||||
{!countUnknown && openCount > 0 && (
|
||||
<Button variant="outlined" onClick={() => navigate(openWorkOrdersHref)}>
|
||||
View open work orders
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -229,6 +229,42 @@ describe("Delete a site from the detail panel", () => {
|
|||
expect(deleteSite).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("holds Delete on reopen until the fresh open work-order count replaces the cached one", async () => {
|
||||
let resolveRecheck: (value: { count: number; workOrderIds: number[] }) => void = () => {};
|
||||
getOpenWorkOrders.mockResolvedValueOnce({ count: 0, workOrderIds: [] });
|
||||
getOpenWorkOrders.mockReturnValueOnce(
|
||||
new Promise((resolve) => {
|
||||
resolveRecheck = resolve;
|
||||
}),
|
||||
);
|
||||
renderAs("Admin");
|
||||
const panel = await openPanel();
|
||||
|
||||
fireEvent.click(within(panel).getByRole("button", { name: "Delete" }));
|
||||
let dialog = await screen.findByRole("dialog", { name: "Delete this site?" });
|
||||
await within(dialog).findByText(
|
||||
"This will permanently remove DAL1 from Sites. This cannot be undone.",
|
||||
);
|
||||
fireEvent.click(within(dialog).getByRole("button", { name: "Cancel" }));
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByRole("dialog", { name: "Delete this site?" })).not.toBeInTheDocument(),
|
||||
);
|
||||
|
||||
fireEvent.click(within(panel).getByRole("button", { name: "Delete" }));
|
||||
dialog = await screen.findByRole("dialog", { name: "Delete this site?" });
|
||||
await waitFor(() => expect(getOpenWorkOrders).toHaveBeenCalledTimes(2));
|
||||
|
||||
expect(within(dialog).getByRole("button", { name: "Delete" })).toBeDisabled();
|
||||
expect(within(dialog).queryByText(/This cannot be undone/)).not.toBeInTheDocument();
|
||||
expect(within(dialog).getByLabelText("Checking open work orders")).toBeInTheDocument();
|
||||
|
||||
resolveRecheck({ count: 1, workOrderIds: [101] });
|
||||
|
||||
expect(await within(dialog).findByText(/It still has 1 open work order —/)).toBeInTheDocument();
|
||||
expect(within(dialog).getByRole("button", { name: "Delete" })).toBeEnabled();
|
||||
expect(deleteSite).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps the site and shows the server's refusal when the API answers 403", async () => {
|
||||
getOpenWorkOrders.mockResolvedValue({ count: 0, workOrderIds: [] });
|
||||
deleteSite.mockRejectedValue(forbidden());
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue