From 69434fe356da7b29a86d20b8426b4ed39ec40a6f Mon Sep 17 00:00:00 2001 From: webdevcody Date: Wed, 7 Jan 2026 23:18:52 -0500 Subject: [PATCH] feat: enhance login view with retry mechanism for server checks - Added useRef to manage AbortController for retry requests in the LoginView component. - Implemented logic to abort any ongoing retry requests before initiating a new server check, improving error handling and user experience during login attempts. --- apps/ui/src/components/views/login-view.tsx | 29 ++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/ui/src/components/views/login-view.tsx b/apps/ui/src/components/views/login-view.tsx index 87a5aef0..445bd937 100644 --- a/apps/ui/src/components/views/login-view.tsx +++ b/apps/ui/src/components/views/login-view.tsx @@ -11,7 +11,7 @@ * checking_setup → redirecting */ -import { useReducer, useEffect } from 'react'; +import { useReducer, useEffect, useRef } from 'react'; import { useNavigate } from '@tanstack/react-router'; import { login, getHttpApiClient, getServerUrlSync } from '@/lib/http-api-client'; import { Button } from '@/components/ui/button'; @@ -176,12 +176,20 @@ async function checkServerAndSession( } } -async function checkSetupStatus(dispatch: React.Dispatch): Promise { +async function checkSetupStatus( + dispatch: React.Dispatch, + signal?: AbortSignal +): Promise { const httpClient = getHttpApiClient(); try { const result = await httpClient.settings.getGlobal(); + // Return early if aborted + if (signal?.aborted) { + return; + } + if (result.success && result.settings) { // Check the setupComplete field from settings // This is set to true when user completes the setup wizard @@ -199,6 +207,10 @@ async function checkSetupStatus(dispatch: React.Dispatch): Promise dispatch({ type: 'REDIRECT', to: '/setup' }); } } catch { + // Return early if aborted + if (signal?.aborted) { + return; + } // If we can't get settings, go to setup to be safe useSetupStore.getState().setSetupComplete(false); dispatch({ type: 'REDIRECT', to: '/setup' }); @@ -232,6 +244,7 @@ export function LoginView() { const navigate = useNavigate(); const setAuthState = useAuthStore((s) => s.setAuthState); const [state, dispatch] = useReducer(reducer, initialState); + const retryControllerRef = useRef(null); // Run initial server/session check on mount. // IMPORTANT: Do not "run once" via a ref guard here. @@ -243,13 +256,19 @@ export function LoginView() { return () => { controller.abort(); + retryControllerRef.current?.abort(); }; }, [setAuthState]); // When we enter checking_setup phase, check setup status useEffect(() => { if (state.phase === 'checking_setup') { - checkSetupStatus(dispatch); + const controller = new AbortController(); + checkSetupStatus(dispatch, controller.signal); + + return () => { + controller.abort(); + }; } }, [state.phase]); @@ -271,8 +290,12 @@ export function LoginView() { // Handle retry button for server errors const handleRetry = () => { + // Abort any previous retry request + retryControllerRef.current?.abort(); + dispatch({ type: 'RETRY_SERVER_CHECK' }); const controller = new AbortController(); + retryControllerRef.current = controller; checkServerAndSession(dispatch, setAuthState, controller.signal); };