diff --git a/frontend/app/auth/callback/page.tsx b/frontend/app/auth/callback/page.tsx index 3ce4c82b4..b05260a8a 100644 --- a/frontend/app/auth/callback/page.tsx +++ b/frontend/app/auth/callback/page.tsx @@ -35,6 +35,8 @@ function AuthCallbackContent() { } sessionStorage.setItem(callbackKey, "true"); + let redirectTimeoutId: NodeJS.Timeout; + const handleCallback = async () => { try { // Get parameters from URL @@ -158,7 +160,7 @@ function AuthCallbackContent() { localStorage.removeItem("auth_redirect_to"); // Redirect to the original page or home - setTimeout(() => { + redirectTimeoutId = setTimeout(() => { router.push(redirectTo); }, 2000); } else { @@ -170,7 +172,7 @@ function AuthCallbackContent() { localStorage.removeItem("auth_purpose"); // Redirect to settings page with success indicator - setTimeout(() => { + redirectTimeoutId = setTimeout(() => { router.push("/settings?oauth_success=true"); }, 2000); } @@ -191,6 +193,7 @@ function AuthCallbackContent() { }; handleCallback(); + return () => clearTimeout(redirectTimeoutId); }, [searchParams, router, refreshAuth]); // Dynamic UI content based on purpose diff --git a/frontend/app/chat/page.tsx b/frontend/app/chat/page.tsx index af9f89857..1deba9056 100644 --- a/frontend/app/chat/page.tsx +++ b/frontend/app/chat/page.tsx @@ -295,6 +295,7 @@ function ChatPage() { // Load conversation data from context useEffect(() => { + let focusTimeoutId: NodeJS.Timeout; // Only load conversation data when: // 1. conversationData exists AND // 2. (It's a different conversation OR we're not streaming and data has changed) AND @@ -486,13 +487,15 @@ function ChatPage() { })); // Focus input when loading a conversation - setTimeout(() => { + focusTimeoutId = setTimeout(() => { chatInputRef.current?.focusInput(); }, 100); } else if (!conversationData) { // No conversation selected (new conversation) lastLoadedConversationRef.current = null; } + + return () => clearTimeout(focusTimeoutId); }, [ conversationData, isUserInteracting, @@ -504,16 +507,18 @@ function ChatPage() { // Handle new conversation creation - only reset messages when placeholderConversation is set useEffect(() => { + let focusTimeoutId: NodeJS.Timeout; if (placeholderConversation && currentConversationId === null) { console.log("Starting new conversation"); setMessages([INITIAL_ASSISTANT_MESSAGE]); lastLoadedConversationRef.current = null; // Focus input when starting a new conversation - setTimeout(() => { + focusTimeoutId = setTimeout(() => { chatInputRef.current?.focusInput(); }, 100); } + return () => clearTimeout(focusTimeoutId); }, [placeholderConversation, currentConversationId]); const { isOnboardingComplete } = useOnboardingState(); diff --git a/frontend/app/onboarding/_components/onboarding-card.tsx b/frontend/app/onboarding/_components/onboarding-card.tsx index 9778d3e8f..ec7e61e07 100644 --- a/frontend/app/onboarding/_components/onboarding-card.tsx +++ b/frontend/app/onboarding/_components/onboarding-card.tsx @@ -272,6 +272,7 @@ const OnboardingCard = ({ // Monitor tasks and call onComplete when all tasks are done useEffect(() => { + let completeTimeoutId: NodeJS.Timeout; if (currentStep === null || !tasks || !isEmbedding) { return; } @@ -404,10 +405,12 @@ const OnboardingCard = ({ // Set to final step to show "Done" setCurrentStep(totalSteps); // Wait a bit before completing - setTimeout(() => { + completeTimeoutId = setTimeout(() => { onComplete(); }, 1000); } + + return () => clearTimeout(completeTimeoutId); }, [ tasks, currentStep, diff --git a/frontend/app/onboarding/_components/onboarding-upload.tsx b/frontend/app/onboarding/_components/onboarding-upload.tsx index bc91a47ff..65b81f618 100644 --- a/frontend/app/onboarding/_components/onboarding-upload.tsx +++ b/frontend/app/onboarding/_components/onboarding-upload.tsx @@ -46,6 +46,7 @@ const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => { // Monitor tasks and call onComplete when file processing is done useEffect(() => { + let completeTimeoutId: NodeJS.Timeout; if (currentStep === null || !tasks || !uploadedTaskId) { return; } @@ -161,7 +162,7 @@ const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => { refetchNudges(); // Wait a bit before completing (after filter is created) - setTimeout(() => { + completeTimeoutId = setTimeout(() => { onComplete(); }, 1000); }); @@ -171,11 +172,13 @@ const OnboardingUpload = ({ onComplete }: OnboardingUploadProps) => { refetchNudges(); // Wait a bit before completing - setTimeout(() => { + completeTimeoutId = setTimeout(() => { onComplete(); }, 1000); } } + + return () => clearTimeout(completeTimeoutId); }, [ tasks, currentStep, diff --git a/frontend/app/settings/_components/agent-settings-section.tsx b/frontend/app/settings/_components/agent-settings-section.tsx index 59fa14f4f..17722a48e 100644 --- a/frontend/app/settings/_components/agent-settings-section.tsx +++ b/frontend/app/settings/_components/agent-settings-section.tsx @@ -148,7 +148,8 @@ export function AgentSettingsSection() { const newParams = new URLSearchParams(searchParams.toString()); newParams.delete("focusLlmModel"); router.replace(`${pathname}?${newParams.toString()}`, { scroll: false }); - setTimeout(() => setOpenLlmSelector(false), 100); + const timeoutId = setTimeout(() => setOpenLlmSelector(false), 100); + return () => clearTimeout(timeoutId); } }, [focusLlmModel, searchParams, router, pathname]);