From af7ca87831434f336bb34e4a00272447fa416fdd Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Fri, 6 Feb 2026 01:59:39 +0530 Subject: [PATCH] Refactor PublicRoute and ModelProvider for improved user flow and state management - Simplified the `PublicRoute` component by removing the onboarding status check, allowing the `Home` component to handle redirection based on user profile loading. - Enhanced the `ModelProvider` component by consolidating the initialization logic and improving error handling during model status checks and downloads. - Introduced cancellation logic in the `ModelProvider` to prevent state updates after component unmounting, ensuring better resource management and preventing memory leaks. --- src/components/PublicRoute.tsx | 7 ++--- src/providers/ModelProvider.tsx | 55 ++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/components/PublicRoute.tsx b/src/components/PublicRoute.tsx index cba430d12..61df14373 100644 --- a/src/components/PublicRoute.tsx +++ b/src/components/PublicRoute.tsx @@ -1,6 +1,5 @@ import { Navigate } from 'react-router-dom'; -import { selectIsOnboarded } from '../store/authSelectors'; import { useAppSelector } from '../store/hooks'; interface PublicRouteProps { @@ -9,13 +8,11 @@ interface PublicRouteProps { } /** - * Public route component that redirects authenticated users - * If logged in and onboarded -> redirect to /home - * If logged in but not onboarded -> redirect to /onboarding + * Public route component that redirects authenticated users to /home. + * Home handles the onboarding redirect once the user profile is loaded. */ const PublicRoute = ({ children, redirectTo }: PublicRouteProps) => { const token = useAppSelector(state => state.auth.token); - const isOnboarded = useAppSelector(selectIsOnboarded); // If user is logged in, always go to home. // Home itself will redirect to onboarding if needed. diff --git a/src/providers/ModelProvider.tsx b/src/providers/ModelProvider.tsx index 66639b729..e97dd85ea 100644 --- a/src/providers/ModelProvider.tsx +++ b/src/providers/ModelProvider.tsx @@ -23,24 +23,33 @@ const ModelProvider = ({ children }: { children: React.ReactNode }) => { state => state.model ); const pollingRef = useRef(false); + const initDone = useRef(false); - // Initial status fetch + availability check + // Initial status fetch + availability check (runs once) useEffect(() => { + if (initDone.current) return; + initDone.current = true; + const init = async () => { + console.log('[ModelProvider] Initializing...'); try { const status = await invoke('model_get_status'); + console.log('[ModelProvider] Initial status:', status); dispatch(setModelStatus(status)); - } catch { - // Non-Tauri environment + } catch (err) { + console.log('[ModelProvider] model_get_status failed (non-Tauri?):', err); + return; // Not a Tauri environment, nothing more to do } try { const avail = await invoke('model_is_available'); + console.log('[ModelProvider] Model available:', avail); if (avail) { - dispatch(setModelStatus({ ...(await invoke('model_get_status')) })); + const status = await invoke('model_get_status'); + dispatch(setModelStatus(status)); } - } catch { - // Non-Tauri environment + } catch (err) { + console.log('[ModelProvider] model_is_available failed:', err); } }; init(); @@ -48,17 +57,37 @@ const ModelProvider = ({ children }: { children: React.ReactNode }) => { // Auto-trigger download on desktop when model is available but not downloaded useEffect(() => { - if (downloadTriggered || !available || downloaded || loading) return; + if (downloadTriggered) { + console.log('[ModelProvider] Auto-download: already triggered, skipping'); + return; + } + if (!available) { + console.log('[ModelProvider] Auto-download: not available yet, waiting'); + return; + } + if (downloaded) { + console.log('[ModelProvider] Auto-download: already downloaded, skipping'); + return; + } + if (loading) { + console.log('[ModelProvider] Auto-download: already loading, skipping'); + return; + } const tryAutoDownload = async () => { try { const currentPlatform = await platform(); - if (currentPlatform === 'android' || currentPlatform === 'ios') return; - } catch { - // Can't detect platform — skip auto-download (likely web) + console.log('[ModelProvider] Platform:', currentPlatform); + if (currentPlatform === 'android' || currentPlatform === 'ios') { + console.log('[ModelProvider] Mobile platform, skipping auto-download'); + return; + } + } catch (err) { + console.log('[ModelProvider] Platform detection failed (likely web), skipping:', err); return; } + console.log('[ModelProvider] Starting auto-download...'); dispatch(setDownloadTriggered(true)); dispatch(setModelLoading(true)); dispatch(setModelError(null)); @@ -66,8 +95,10 @@ const ModelProvider = ({ children }: { children: React.ReactNode }) => { try { await invoke('model_start_download'); const status = await invoke('model_get_status'); + console.log('[ModelProvider] Download started, status:', status); dispatch(setModelStatus(status)); } catch (err) { + console.error('[ModelProvider] Auto-download failed:', err); dispatch(setModelError(err instanceof Error ? err.message : 'Failed to download model')); } }; @@ -83,6 +114,7 @@ const ModelProvider = ({ children }: { children: React.ReactNode }) => { } pollingRef.current = true; + console.log('[ModelProvider] Polling started (loading=true)'); const interval = setInterval(async () => { if (!pollingRef.current) return; @@ -90,10 +122,11 @@ const ModelProvider = ({ children }: { children: React.ReactNode }) => { const status = await invoke('model_get_status'); dispatch(setModelStatus(status)); if (!status.loading) { + console.log('[ModelProvider] Polling stopped (loading done)', status); pollingRef.current = false; } } catch { - // ignore + // ignore polling errors } }, POLL_INTERVAL);