canvas-query-cache.ts1.9 KBView on GitHub
import { getBrowserQueryClient } from '@/lib/browser-query-client';
import type { CanvasViewConfig } from '@/modules/canvas/types/canvas-types';

/**
 * tRPC's tanstack query key for `canvas.getCanvases`, without an input — TanStack matches by
 * prefix, so this covers every variant (homeViewOnly / includeShared combinations).
 */
const CANVAS_LIST_QUERY_KEY = [['canvas', 'getCanvases']];

/** The raw row shape `canvas.getCanvases` returns (snake_case — it is a `SELECT c.*`). */
type CachedCanvasRow = {
  id: string;
  view_config: CanvasViewConfig;
  updated_at: string | Date;
};

/**
 * Writes a just-saved viewConfig into the cached `canvas.getCanvases` response.
 *
 * `canvasSlice` is hydrated from that query on every mount of a consumer (client-providers,
 * PipelineView, ReportsView) and the response is persisted to IndexedDB, so it also survives a
 * reload. Saving only to the server leaves the pre-save row in the cache: the next mount inside
 * the staleTime window rehydrates the store from it and the user's filter/sort/layout change
 * silently reverts — and the next save then writes that stale config back to the server, losing
 * the change for good. The change is already persisted; this stops the client from serving the
 * version from before it.
 */
export function syncSavedViewConfigToQueryCache(
  canvasId: string,
  viewConfig: CanvasViewConfig,
  updatedAt: string,
): void {
  const queryClient = getBrowserQueryClient();
  if (!queryClient) return;

  queryClient.setQueriesData({ queryKey=[redacted] }, (data: unknown) => {
    if (!Array.isArray(data)) return data;

    let matched = false;
    const next = data.map((row) => {
      const canvasRow = row as CachedCanvasRow;
      if (canvasRow?.id !== canvasId) return row;
      matched = true;
      return { ...canvasRow, view_config: viewConfig, updated_at: updatedAt };
    });

    return matched ? next : data;
  });
}