mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 15:03:57 +00:00
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.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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<ModelStatus>('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<boolean>('model_is_available');
|
||||
console.log('[ModelProvider] Model available:', avail);
|
||||
if (avail) {
|
||||
dispatch(setModelStatus({ ...(await invoke<ModelStatus>('model_get_status')) }));
|
||||
const status = await invoke<ModelStatus>('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<ModelStatus>('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<ModelStatus>('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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user