mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 08:32:54 +00:00
- Add migration for consolidation approvals table and status enum - Create ConsolidationApprovalService to handle approval logic - Implement repository for managing consolidation approvals - Add entity for consolidation approval with necessary fields - Develop frontend components for displaying and managing consolidation approvals - Create tests for consolidation approval service to ensure correct behavior
66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import { MutationCache, QueryClient } from "@tanstack/react-query";
|
|
|
|
import type { InvalidatesMeta, UpdatesMeta } from "@/utils/endpoint";
|
|
|
|
/**
|
|
* Single app-wide React Query client (do not nest additional providers).
|
|
*
|
|
* Declarative invalidation: any mutation built via `api.*.mutationOptions()`
|
|
* (see `services/api.ts` + `utils/endpoint.ts`) carries an `invalidates`
|
|
* function in its `meta`. The shared `MutationCache` below runs it on success
|
|
* and invalidates the returned query keys — so invalidation is declared once in
|
|
* the endpoint definition rather than re-wired in every component.
|
|
*/
|
|
export const queryClient = new QueryClient({
|
|
mutationCache: new MutationCache({
|
|
onSuccess: (data, variables, _context, mutation) => {
|
|
// Seed first: endpoints that return the entity they just changed write it
|
|
// straight into its cache key, so the screen updates from the response
|
|
// instead of round-tripping for data it already holds.
|
|
const updates = mutation.meta?.updates as UpdatesMeta | undefined;
|
|
const seeded: readonly unknown[][] = [];
|
|
if (typeof updates === "function") {
|
|
for (const [queryKey, value] of updates(variables, data)) {
|
|
queryClient.setQueryData(queryKey, value);
|
|
seeded.push(queryKey as unknown[]);
|
|
}
|
|
}
|
|
|
|
const invalidates = mutation.meta?.invalidates as
|
|
| InvalidatesMeta
|
|
| undefined;
|
|
if (typeof invalidates !== "function") return;
|
|
|
|
for (const queryKey of invalidates(variables, data)) {
|
|
void queryClient.invalidateQueries({
|
|
queryKey,
|
|
// A seeded key already holds the authoritative value from this very
|
|
// response — invalidating it would refetch it right back.
|
|
predicate: seeded.length
|
|
? (query) =>
|
|
!seeded.some(
|
|
(key) =>
|
|
key.length === query.queryKey.length &&
|
|
key.every((part, i) => Object.is(part, query.queryKey[i])),
|
|
)
|
|
: undefined,
|
|
});
|
|
}
|
|
},
|
|
// Mutation failures are surfaced globally by the axios interceptor in
|
|
// auth/http.ts (server-message toast on every non-401 failure), so no
|
|
// onError toast here — it would double up.
|
|
}),
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: 1,
|
|
// staleTime: 30_000,
|
|
staleTime:0,
|
|
// Data freshness is driven by mutation invalidation (MutationCache above),
|
|
// socket pushes, and explicit polling — not by tab focus. Focus refetch
|
|
// just re-fires every mounted query each time the window is refocused.
|
|
refetchOnWindowFocus: false,
|
|
},
|
|
},
|
|
});
|