mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
fix(medications): stop the delete confirm hanging in a spinner
Deleting a medication from the danger zone awaited a prefix-invalidate of the "medications" key bundle before navigating. That bundle covers the detail page's own active query, so the invalidation refetched the just- deleted resource, hit a 404, retried with backoff, and never resolved — the confirm button spun forever even though the delete had persisted. Evict the detail query before invalidating, navigate to the list first, then fire-and-forget the dependent-bundle invalidation. The busy state is also cleared on the failed-response path. The detail query opts out of retries so a deleted-resource refetch never burns a backoff cycle.
This commit is contained in:
1 parent
b3f61d0c75
commit
ddb08b048a
2 files changed
+29
-6
No files matched your search
@@ -132,6 +132,11 @@ export default function MedicationDetailPage({
|
||||
return (await res.json()).data as MedicationDetailSnapshot;
|
||||
},
|
||||
enabled: isAuthenticated,
|
||||
// A deleted medication 404s here. Don't burn a retry/backoff cycle on
|
||||
// a resource that no longer exists — the delete handler evicts this
|
||||
// key on success, but `retry: false` hardens any caller that
|
||||
// prefix-invalidates `["medications"]` while this page is mounted.
|
||||
retry: false,
|
||||
});
|
||||
|
||||
// v1.7.2 W3 — derive the wizard payload purely to feed the read-only
|
||||
|
||||
@@ -47,7 +47,11 @@ import { Card } from "@/components/ui/card";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { invalidateKeys, medicationDependentKeys } from "@/lib/query-keys";
|
||||
import {
|
||||
invalidateKeys,
|
||||
medicationDependentKeys,
|
||||
queryKeys,
|
||||
} from "@/lib/query-keys";
|
||||
|
||||
const PAUSE_SWITCH_ID = "medication-detail-pause-switch";
|
||||
const PAUSE_TITLE_ID = "medication-detail-pause-title";
|
||||
@@ -283,15 +287,29 @@ export function DangerZoneBody({
|
||||
});
|
||||
if (!res.ok) {
|
||||
toast.error(t("medications.detail.zone.delete.failed"));
|
||||
setTier3bBusy(false);
|
||||
return;
|
||||
}
|
||||
// Cache cascade first so the list page paints without the
|
||||
// medication, then route. The bundle includes
|
||||
// `compliance-chart-inline` so the inline chart's stale cache
|
||||
// evicts before the user lands on the list.
|
||||
await invalidateKeys(queryClient, medicationDependentKeys);
|
||||
// Drop the deleted medication's own detail query before the
|
||||
// prefix-invalidate below. `medicationDependentKeys` carries
|
||||
// `["medications"]`, which covers the active `["medications", id]`
|
||||
// detail query on this page; awaiting that invalidation refetched
|
||||
// a now-404 resource, retried, and hung the spinner forever (the
|
||||
// delete had already persisted server-side). `removeQueries`
|
||||
// evicts the dead key so the prefix-invalidate can't refetch it.
|
||||
queryClient.removeQueries({
|
||||
queryKey: queryKeys.medicationDetail(medicationId),
|
||||
});
|
||||
// Navigate away first — we're leaving the detail page, so the
|
||||
// dependent-bundle invalidation can settle in the background while
|
||||
// the list page mounts and re-reads `["medications"]` fresh.
|
||||
toast.success(t("medications.detail.zone.delete.toast"));
|
||||
setDeleteDialogOpen(false);
|
||||
router.push("/medications");
|
||||
// Fire-and-forget the dependent-bundle invalidation (list /
|
||||
// analytics / compliance / inline chart). Not awaited: navigation
|
||||
// already happened and a transient refetch must not block it.
|
||||
void invalidateKeys(queryClient, medicationDependentKeys);
|
||||
} catch {
|
||||
toast.error(t("medications.detail.zone.delete.failed"));
|
||||
setTier3bBusy(false);
|
||||
|
||||
Reference in new issue
Block a user