Spaces:
Sleeping
Sleeping
| import { useEffect, useState } from 'react'; | |
| import { Routes, Route, Navigate } from 'react-router-dom'; | |
| import { useAuthStore } from './store/authStore'; | |
| import { ThemeProvider } from './contexts/ThemeContext'; | |
| import AppLayout from './components/Layout/AppLayout'; | |
| import LoginForm from './components/Auth/LoginForm'; | |
| import RegisterForm from './components/Auth/RegisterForm'; | |
| import ForgotPassword from './components/Auth/ForgotPassword'; | |
| import ResetPassword from './components/Auth/ResetPassword'; | |
| import AuthCallback from './components/Auth/AuthCallback'; | |
| import Dashboard from './components/Dashboard/Dashboard'; | |
| import SettingsPage from './components/Settings/SettingsPage'; | |
| import ProjectEditor from './components/ProjectEditor/ProjectEditor'; | |
| import ErrorBoundary from './components/ErrorBoundary'; | |
| import WebSocketProvider from './components/WebSocketProvider'; | |
| function ProtectedRoute({ children }: { children: React.ReactNode }) { | |
| const { token, initialized } = useAuthStore(); | |
| if (!initialized) { | |
| return ( | |
| <div className="min-h-screen flex items-center justify-center bg-surface-950"> | |
| <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-500" /> | |
| </div> | |
| ); | |
| } | |
| if (!token) return <Navigate to="/login" replace />; | |
| return <>{children}</>; | |
| } | |
| function PublicRoute({ children }: { children: React.ReactNode }) { | |
| const { token, initialized } = useAuthStore(); | |
| if (!initialized) { | |
| return ( | |
| <div className="min-h-screen flex items-center justify-center bg-surface-950"> | |
| <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-500" /> | |
| </div> | |
| ); | |
| } | |
| if (token) return <Navigate to="/dashboard" replace />; | |
| return <>{children}</>; | |
| } | |
| export default function App() { | |
| const init = useAuthStore((s) => s.init); | |
| const [ready, setReady] = useState(false); | |
| useEffect(() => { | |
| init().finally(() => setReady(true)); | |
| }, [init]); | |
| if (!ready) return null; | |
| return ( | |
| <WebSocketProvider> | |
| <ThemeProvider> | |
| <div className="h-screen overflow-hidden"> | |
| <Routes> | |
| <Route path="/" element={<Navigate to="/dashboard" replace />} /> | |
| <Route path="/login" element={<PublicRoute><LoginForm /></PublicRoute>} /> | |
| <Route path="/register" element={<PublicRoute><RegisterForm /></PublicRoute>} /> | |
| <Route path="/auth/callback" element={<AuthCallback />} /> | |
| <Route path="/forgot-password" element={<PublicRoute><ForgotPassword /></PublicRoute>} /> | |
| <Route path="/reset-password" element={<PublicRoute><ResetPassword /></PublicRoute>} /> | |
| <Route | |
| path="/dashboard" | |
| element={ | |
| <ProtectedRoute> | |
| <ErrorBoundary> | |
| <AppLayout> | |
| <Dashboard /> | |
| </AppLayout> | |
| </ErrorBoundary> | |
| </ProtectedRoute> | |
| } | |
| /> | |
| <Route | |
| path="/project/:id" | |
| element={ | |
| <ProtectedRoute> | |
| <ErrorBoundary> | |
| <ProjectEditor /> | |
| </ErrorBoundary> | |
| </ProtectedRoute> | |
| } | |
| /> | |
| <Route path="*" element={<Navigate to="/dashboard" replace />} /> | |
| <Route | |
| path="/settings" | |
| element={ | |
| <ProtectedRoute> | |
| <ErrorBoundary> | |
| <AppLayout> | |
| <SettingsPage /> | |
| </AppLayout> | |
| </ErrorBoundary> | |
| </ProtectedRoute> | |
| } | |
| /> | |
| </Routes> | |
| </div> | |
| </ThemeProvider> | |
| </WebSocketProvider> | |
| ); | |
| } | |