/** * useConstructorData Hook * * Orchestrates all data fetching for the constructor page using React Query. * Replaces the manual loadData function with cached, deduplicated queries. */ import { useMemo } from 'react'; import { useProjectQuery } from './queries/useProjectQuery'; import { usePagesQuery } from './queries/usePagesQuery'; import { useAssetsQuery } from './queries/useAssetsQuery'; import { useElementDefaultsQuery } from './queries/useElementDefaultsQuery'; import { extractPageLinksAndElements } from '../lib/extractPageLinks'; import type { TourPage, Asset } from '../types/entities'; import type { CanvasElementType, CanvasElement } from '../types/constructor'; import type { PreloadPageLink, PreloadElement } from '../types/preload'; interface UseConstructorDataParams { projectId: string | undefined; isAuthReady: boolean; } // Stable empty references to prevent infinite loops from identity changes const EMPTY_ELEMENT_DEFAULTS: Partial< Record> > = {}; const EMPTY_PAGES: TourPage[] = []; const EMPTY_ASSETS: Asset[] = []; interface UseConstructorDataResult { // Project project: { name: string } | null; projectName: string; // Pages pages: TourPage[]; pageLinks: PreloadPageLink[]; allPagesPreloadElements: PreloadElement[]; // Assets assets: Asset[]; // Element Defaults uiElementDefaultsByType: Partial< Record> >; // Loading state isLoading: boolean; isError: boolean; error: Error | null; // Refetch function refetch: () => Promise; } export function useConstructorData({ projectId, isAuthReady, }: UseConstructorDataParams): UseConstructorDataResult { // Enable queries only when we have projectId and auth is ready const enabled = Boolean(projectId) && isAuthReady; // Fetch project const projectQuery = useProjectQuery(enabled ? projectId : undefined); // Fetch pages (dev environment for constructor) const pagesQuery = usePagesQuery(enabled ? projectId : undefined, 'dev'); // Fetch assets const assetsQuery = useAssetsQuery(enabled ? projectId : undefined, { limit: 500, }); // Fetch element defaults const elementDefaultsQuery = useElementDefaultsQuery( enabled ? projectId : undefined, ); // Extract page links and preload elements from pages const { pageLinks, allPagesPreloadElements } = useMemo(() => { if (!pagesQuery.data || pagesQuery.data.length === 0) { return { pageLinks: [] as PreloadPageLink[], allPagesPreloadElements: [] as PreloadElement[], }; } const { pageLinks: links, preloadElements: elements } = extractPageLinksAndElements(pagesQuery.data as TourPage[]); return { pageLinks: links, allPagesPreloadElements: elements }; }, [pagesQuery.data]); // Combine loading states const isLoading = projectQuery.isLoading || pagesQuery.isLoading || assetsQuery.isLoading || elementDefaultsQuery.isLoading; // Combine error states const isError = projectQuery.isError || pagesQuery.isError || assetsQuery.isError || elementDefaultsQuery.isError; const error = projectQuery.error || pagesQuery.error || assetsQuery.error || elementDefaultsQuery.error; // Refetch all queries const refetch = async () => { await Promise.all([ projectQuery.refetch(), pagesQuery.refetch(), assetsQuery.refetch(), elementDefaultsQuery.refetch(), ]); }; return { // Project project: projectQuery.data || null, projectName: projectQuery.data?.name || '', // Pages pages: (pagesQuery.data as TourPage[]) || EMPTY_PAGES, pageLinks, allPagesPreloadElements, // Assets assets: (assetsQuery.data as Asset[]) || EMPTY_ASSETS, // Element Defaults uiElementDefaultsByType: elementDefaultsQuery.data || EMPTY_ELEMENT_DEFAULTS, // Loading state isLoading, isError, error: error instanceof Error ? error : null, // Refetch refetch, }; } export default useConstructorData;