From 0e8d8e7d5eb374af96617478af2bfef827a565ed Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:15:03 -0600 Subject: [PATCH] Fix blank stations page by waiting for auth initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add useIsAuthInitialized hook to auth-gate for reactive auth state - Returns true once auth token is acquired and ready - Waits for waitForAuthInit() promise to resolve - Update useSavedStations hook to wait for auth before fetching - Add 'enabled: isAuthInitialized' to useQuery config - Prevents 401 errors from requests made before token is ready - Fixes race condition where hook fires before interceptor is set up The stations page was blank because useSavedStations() made an API call with refetchOnMount:true before the auth token interceptor was added, causing a 401 response that made the component unmount/remount, creating a React DOM error in the error boundary. Now the hook waits for isAuthInitialized to be true before making the initial API call, ensuring the token interceptor is ready. 🤖 Generated with Claude Code Co-Authored-By: Claude --- frontend/src/core/auth/auth-gate.ts | 24 +++++++++++++++++++ .../stations/hooks/useSavedStations.ts | 6 ++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/frontend/src/core/auth/auth-gate.ts b/frontend/src/core/auth/auth-gate.ts index aa074a2..6b6391b 100644 --- a/frontend/src/core/auth/auth-gate.ts +++ b/frontend/src/core/auth/auth-gate.ts @@ -3,6 +3,8 @@ * @ai-context Prevents race conditions between IndexedDB init and API calls */ +import { useState, useEffect } from 'react'; + // Global authentication readiness state let authInitialized = false; let authInitPromise: Promise | null = null; @@ -99,4 +101,26 @@ const processRequestQueue = async () => { isProcessingQueue = false; console.log('[Auth Gate] Finished processing queued requests'); +}; + +/** + * React hook to track auth initialization state + * Returns true once auth is fully initialized with token + */ +export const useIsAuthInitialized = () => { + const [initialized, setInitialized] = useState(authInitialized); + + useEffect(() => { + if (authInitialized) { + setInitialized(true); + return; + } + + // Wait for auth to initialize + waitForAuthInit().then(() => { + setInitialized(true); + }); + }, []); + + return initialized; }; \ No newline at end of file diff --git a/frontend/src/features/stations/hooks/useSavedStations.ts b/frontend/src/features/stations/hooks/useSavedStations.ts index 8fba966..4524273 100644 --- a/frontend/src/features/stations/hooks/useSavedStations.ts +++ b/frontend/src/features/stations/hooks/useSavedStations.ts @@ -3,6 +3,7 @@ */ import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useIsAuthInitialized } from '../../../core/auth/auth-gate'; import { stationsApi } from '../api/stations.api'; import { SavedStation } from '../types/stations.types'; @@ -33,12 +34,15 @@ interface UseSavedStationsOptions { * ``` */ export function useSavedStations(options?: UseSavedStationsOptions) { + const isAuthInitialized = useIsAuthInitialized(); + return useQuery({ queryKey: SAVED_STATIONS_QUERY_KEY, queryFn: () => stationsApi.getSavedStations(), staleTime: options?.staleTime ?? 5 * 60 * 1000, // 5 minutes default refetchOnWindowFocus: options?.refetchOnWindowFocus ?? true, - refetchOnMount: true + refetchOnMount: true, + enabled: isAuthInitialized // Only fetch once auth is initialized }); }