import type { QueryKey } from "@tanstack/react-query"; import { queryClient } from "./queryClient"; import { readCachedValue, writeCachedValue } from "./offlineCache"; const inFlightRequests = new Map>(); export function normalizeTeamSnapCacheScope(scope?: string | number | null): string { const value = scope == null ? "" : String(scope).trim(); return value || "anonymous"; } function buildCacheParts(scope: string | number | null | undefined, resource: string, parts: readonly unknown[]): readonly unknown[] { return ["teamsnap", normalizeTeamSnapCacheScope(scope), resource, ...parts]; } function cacheKey(parts: readonly unknown[]): string { return JSON.stringify(parts); } function startFreshFetch( cacheParts: readonly unknown[], queryKey: QueryKey, fetchFresh: () => Promise, ): Promise { const key = cacheKey(cacheParts); const existing = inFlightRequests.get(key); if (existing) { return existing as Promise; } const request = fetchFresh() .then((data) => { writeCachedValue(cacheParts, data); queryClient.setQueryData(queryKey, data); return data; }) .finally(() => { inFlightRequests.delete(key); }); inFlightRequests.set(key, request); return request; } export async function staleWhileRevalidateTeamSnap({ cacheParts, queryKey, fetchFresh, }: { cacheParts: readonly unknown[]; queryKey: QueryKey; fetchFresh: () => Promise; }): Promise { const cached = readCachedValue(cacheParts); if (cached) { void startFreshFetch(cacheParts, queryKey, fetchFresh).catch(() => undefined); return cached.data; } return startFreshFetch(cacheParts, queryKey, fetchFresh); } export const teamSnapQueryKeys = { me(scope?: string | number | null): QueryKey { return buildCacheParts(scope, "me", []); }, teams(scope?: string | number | null): QueryKey { return buildCacheParts(scope, "teams", []); }, members(scope: string | number | null | undefined, teamId: string): QueryKey { return buildCacheParts(scope, "members", [teamId]); }, events(scope: string | number | null | undefined, teamId: string): QueryKey { return buildCacheParts(scope, "events", [teamId]); }, availabilities(scope: string | number | null | undefined, teamId: string, eventId?: string): QueryKey { return buildCacheParts(scope, "availabilities", [teamId, eventId ?? ""]); }, assignments(scope: string | number | null | undefined, teamId: string, eventId?: string): QueryKey { return buildCacheParts(scope, "assignments", [teamId, eventId ?? ""]); }, eventLineup(scope: string | number | null | undefined, teamId: string, eventId: string): QueryKey { return buildCacheParts(scope, "eventLineup", [teamId, eventId]); }, };