diff --git a/frontend/app/api/queries/useGetConversationsQuery.ts b/frontend/app/api/queries/useGetConversationsQuery.ts index d77b7eff..66862605 100644 --- a/frontend/app/api/queries/useGetConversationsQuery.ts +++ b/frontend/app/api/queries/useGetConversationsQuery.ts @@ -4,6 +4,7 @@ import { useQueryClient, } from "@tanstack/react-query"; import type { EndpointType } from "@/contexts/chat-context"; +import { useChat } from "@/contexts/chat-context"; export interface RawConversation { response_id: string; @@ -50,6 +51,7 @@ export const useGetConversationsQuery = ( options?: Omit, ) => { const queryClient = useQueryClient(); + const { isOnboardingComplete } = useChat(); async function getConversations(context: { signal?: AbortSignal }): Promise { try { @@ -95,6 +97,11 @@ export const useGetConversationsQuery = ( } } + // Extract enabled from options and combine with onboarding completion check + // Query is only enabled if onboarding is complete AND the caller's enabled condition is met + const callerEnabled = options?.enabled ?? true; + const enabled = isOnboardingComplete && callerEnabled; + const queryResult = useQuery( { queryKey: ["conversations", endpoint, refreshTrigger], @@ -106,6 +113,7 @@ export const useGetConversationsQuery = ( refetchOnMount: false, // Don't refetch on every mount refetchOnWindowFocus: false, // Don't refetch when window regains focus ...options, + enabled, // Override enabled after spreading options to ensure onboarding check is applied }, queryClient, ); diff --git a/frontend/app/api/queries/useProviderHealthQuery.ts b/frontend/app/api/queries/useProviderHealthQuery.ts index 6586e6dd..476a3780 100644 --- a/frontend/app/api/queries/useProviderHealthQuery.ts +++ b/frontend/app/api/queries/useProviderHealthQuery.ts @@ -40,8 +40,8 @@ export const useProviderHealthQuery = ( ) => { const queryClient = useQueryClient(); - // Get chat error state from context (ChatProvider wraps the entire app in layout.tsx) - const { hasChatError, setChatError } = useChat(); + // Get chat error state and onboarding completion from context (ChatProvider wraps the entire app in layout.tsx) + const { hasChatError, setChatError, isOnboardingComplete } = useChat(); const { data: settings = {} } = useGetSettingsQuery(); @@ -143,7 +143,10 @@ export const useProviderHealthQuery = ( refetchOnWindowFocus: false, // Disabled to reduce unnecessary calls on tab switches refetchOnMount: true, staleTime: 30000, // Consider data stale after 30 seconds - enabled: !!settings?.edited && options?.enabled !== false, // Only run after onboarding is complete + enabled: + !!settings?.edited && + isOnboardingComplete && + options?.enabled !== false, // Only run after onboarding is complete ...options, }, queryClient, diff --git a/frontend/components/chat-renderer.tsx b/frontend/components/chat-renderer.tsx index 6804b065..cceb99c7 100644 --- a/frontend/components/chat-renderer.tsx +++ b/frontend/components/chat-renderer.tsx @@ -47,8 +47,7 @@ export function ChatRenderer({ refreshConversations, startNewConversation, setConversationFilter, - setCurrentConversationId, - setPreviousResponseIds, + setOnboardingComplete, } = useChat(); // Initialize onboarding state based on local storage and settings @@ -170,6 +169,9 @@ export function ChatRenderer({ localStorage.removeItem(ONBOARDING_UPLOAD_STEPS_KEY); } + // Mark onboarding as complete in context + setOnboardingComplete(true); + // Clear ALL conversation state so next message starts fresh await startNewConversation(); @@ -202,6 +204,8 @@ export function ChatRenderer({ localStorage.removeItem(ONBOARDING_CARD_STEPS_KEY); localStorage.removeItem(ONBOARDING_UPLOAD_STEPS_KEY); } + // Mark onboarding as complete in context + setOnboardingComplete(true); // Store the OpenRAG docs filter as default for new conversations storeDefaultFilterForNewConversations(false); setShowLayout(true); diff --git a/frontend/contexts/chat-context.tsx b/frontend/contexts/chat-context.tsx index 59b5edeb..611c3324 100644 --- a/frontend/contexts/chat-context.tsx +++ b/frontend/contexts/chat-context.tsx @@ -10,6 +10,7 @@ import { useRef, useState, } from "react"; +import { ONBOARDING_STEP_KEY } from "@/lib/constants"; export type EndpointType = "chat" | "langflow"; @@ -81,6 +82,8 @@ interface ChatContextType { setConversationFilter: (filter: KnowledgeFilter | null, responseId?: string | null) => void; hasChatError: boolean; setChatError: (hasError: boolean) => void; + isOnboardingComplete: boolean; + setOnboardingComplete: (complete: boolean) => void; } const ChatContext = createContext(undefined); @@ -111,6 +114,37 @@ export function ChatProvider({ children }: ChatProviderProps) { const [conversationFilter, setConversationFilterState] = useState(null); const [hasChatError, setChatError] = useState(false); + + // Check if onboarding is complete (onboarding step key should be null) + const [isOnboardingComplete, setIsOnboardingComplete] = useState(() => { + if (typeof window === "undefined") return false; + return localStorage.getItem(ONBOARDING_STEP_KEY) === null; + }); + + // Sync onboarding completion state with localStorage + useEffect(() => { + const checkOnboarding = () => { + if (typeof window !== "undefined") { + setIsOnboardingComplete( + localStorage.getItem(ONBOARDING_STEP_KEY) === null, + ); + } + }; + + // Check on mount + checkOnboarding(); + + // Listen for storage events (for cross-tab sync) + window.addEventListener("storage", checkOnboarding); + + return () => { + window.removeEventListener("storage", checkOnboarding); + }; + }, []); + + const setOnboardingComplete = useCallback((complete: boolean) => { + setIsOnboardingComplete(complete); + }, []); // Listen for ingestion failures and set chat error flag useEffect(() => { @@ -375,6 +409,8 @@ export function ChatProvider({ children }: ChatProviderProps) { setConversationFilter, hasChatError, setChatError, + isOnboardingComplete, + setOnboardingComplete, }), [ endpoint, @@ -396,6 +432,8 @@ export function ChatProvider({ children }: ChatProviderProps) { conversationFilter, setConversationFilter, hasChatError, + isOnboardingComplete, + setOnboardingComplete, ], );