fix(web): make invalidation hooks async with Promise.all and fix cross-view staleness

- useInvalidateTimeline and useInvalidatePlanningViews now return
  Promise.all instead of fire-and-forget void calls
- Timeline mutations now use useInvalidatePlanningViews to also
  invalidate allocation list views, preventing stale data
- AllocationsClient sequential awaits replaced with single
  invalidatePlanningViews() call (parallel invalidation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-11 08:24:33 +02:00
parent f18777c365
commit f3fa902773
11 changed files with 372 additions and 229 deletions
@@ -5,6 +5,7 @@ import { useUrlFilters } from "~/hooks/useUrlFilters.js";
import { useLocalStorage } from "~/hooks/useLocalStorage.js";
import { formatDate } from "~/lib/format.js";
import { trpc } from "~/lib/trpc/client.js";
import { useInvalidatePlanningViews } from "~/hooks/useInvalidatePlanningViews.js";
import { AllocationModal } from "./AllocationModal.js";
import type {
AllocationLike,
@@ -171,6 +172,7 @@ export function AllocationsClient() {
const selection = useSelection();
const utils = trpc.useUtils();
const invalidatePlanningViews = useInvalidatePlanningViews();
const { canViewCosts } = usePermissions();
// ─── Column visibility ────────────────────────────────────────────────────
@@ -205,31 +207,23 @@ export function AllocationsClient() {
const allocationQueryFailure = isError ? getAllocationQueryFailure(error) : null;
const deleteDemandMutation = trpc.allocation.deleteDemandRequirement.useMutation({
onSuccess: async () => {
await utils.allocation.list.invalidate();
await utils.allocation.listView.invalidate();
},
onSuccess: () => invalidatePlanningViews(),
});
const deleteAssignmentMutation = trpc.allocation.deleteAssignment.useMutation({
onSuccess: async () => {
await utils.allocation.list.invalidate();
await utils.allocation.listView.invalidate();
},
onSuccess: () => invalidatePlanningViews(),
});
const batchDeleteMutation = trpc.allocation.batchDelete.useMutation({
onSuccess: async () => {
await utils.allocation.list.invalidate();
await utils.allocation.listView.invalidate();
await invalidatePlanningViews();
selection.clear();
},
});
const batchStatusMutation = trpc.allocation.batchUpdateStatus.useMutation({
onSuccess: async () => {
await utils.allocation.list.invalidate();
await utils.allocation.listView.invalidate();
await invalidatePlanningViews();
selection.clear();
setShowStatusToast(true);
},
@@ -237,8 +231,7 @@ export function AllocationsClient() {
const batchDateShiftMutation = trpc.timeline.batchShiftAllocations.useMutation({
onSuccess: async () => {
await utils.allocation.list.invalidate();
await utils.allocation.listView.invalidate();
await invalidatePlanningViews();
selection.clear();
setShowDateShiftModal(false);
},