| ```typescript |
| import { Routes, Route } from 'react-router-dom' |
| import { useEffect } from 'react' |
| import { useAppDispatch, useAppSelector } from './hooks/redux' |
| import { fetchUser } from './store/slices/authSlice' |
| import { setTheme } from './store/slices/themeSlice' |
| |
| // Layouts |
| import MainLayout from './components/layouts/MainLayout' |
| import AuthLayout from './components/layouts/AuthLayout' |
| |
| // Pages |
| import HomePage from './pages/HomePage' |
| import WatchPage from './pages/WatchPage' |
| import ChannelPage from './pages/ChannelPage' |
| import SearchPage from './pages/SearchPage' |
| import UploadPage from './pages/UploadPage' |
| import LoginPage from './pages/LoginPage' |
| import RegisterPage from './pages/RegisterPage' |
| import NotFoundPage from './pages/NotFoundPage' |
| |
| function App() { |
| const dispatch = useAppDispatch() |
| const { user, isLoading } = useAppSelector((state) => state.auth) |
| const { theme } = useAppSelector((state) => state.theme) |
| |
| useEffect(() => { |
| // Initialize theme |
| const savedTheme = localStorage.getItem('theme') as 'light' | 'dark' || 'light' |
| dispatch(setTheme(savedTheme)) |
| document.documentElement.classList.toggle('dark', savedTheme === 'dark') |
| |
| // Check for existing token and fetch user |
| const token = localStorage.getItem('token') |
| if (token && !user) { |
| dispatch(fetchUser()) |
| } |
| }, [dispatch, user]) |
| |
| useEffect(() => { |
| // Apply theme changes |
| document.documentElement.classList.toggle('dark', theme === 'dark') |
| localStorage.setItem('theme', theme) |
| }, [theme]) |
| |
| if (isLoading) { |
| return ( |
| <div className="flex items-center justify-center min-h-screen"> |
| <div className="animate-spin rounded-full h-32 w-32 border-b-2 border-youtube-red"></div> |
| </div> |
| ) |
| } |
| |
| return ( |
| <div className="min-h-screen bg-youtube-light dark:bg-youtube-dark"> |
| <Routes> |
| <Route path="/" element={<MainLayout />}> |
| <Route index element={<HomePage />} /> |
| <Route path="watch/:id" element={<WatchPage />} /> |
| <Route path="channel/:id" element={<ChannelPage />} /> |
| <Route path="search" element={<SearchPage />} /> |
| <Route path="upload" element={<UploadPage />} /> |
| </Route> |
| |
| <Route path="/auth" element={<AuthLayout />}> |
| <Route path="login" element={<LoginPage />} /> |
| <Route path="register" element={<RegisterPage />} /> |
| </Route> |
| |
| <Route path="*" element={<NotFoundPage />} /> |
| </Routes> |
| </div> |
| ) |
| } |
| |
| export default App |
| ``` |
|
|
| Теперь создам Redux store и slices: |