import { BrowserRouter, Routes, Route, Navigate, useNavigate } from 'react-router-dom' import { useState, useEffect, useRef } from 'react' import { initTelegramApp, getTelegramUser, isThirdPartyClient } from './utils/telegram' import { verifyAuth, authWithTelegramOAuth, verifySession } from './utils/api' import { initTheme } from './utils/theme' import Layout from './components/Layout' import Feed from './pages/Feed' import Search from './pages/Search' import Notifications from './pages/Notifications' import Profile from './pages/Profile' import UserProfile from './pages/UserProfile' import CommentsPage from './pages/CommentsPage' import PostMenuPage from './pages/PostMenuPage' import TelegramLogin from './components/TelegramLogin' import './styles/index.css' function AppContent() { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [showLogin, setShowLogin] = useState(false) const navigate = useNavigate() const startParamProcessed = useRef(false) // Флаг для обработки startParam только один раз const initAppCalled = useRef(false) // Флаг чтобы initApp вызывался только один раз useEffect(() => { // Инициализировать тему только один раз initTheme() // Инициализировать приложение только если еще не было вызвано if (!initAppCalled.current) { initAppCalled.current = true initApp() } }, []) const initApp = async () => { try { // Инициализация Telegram Web App initTelegramApp() // Проверить наличие Telegram Web App API const tg = window.Telegram?.WebApp // Дать время на полную инициализацию Telegram Web App await new Promise(resolve => setTimeout(resolve, 300)) // Проверить наличие initData (главный индикатор что мы в Telegram) const initData = tg?.initData || '' if (initData) { // Есть initData - пробуем авторизоваться через API try { const userData = await verifyAuth() // Сохранить сессию для будущих загрузок localStorage.setItem('nakama_user', JSON.stringify(userData)) localStorage.setItem('nakama_auth_type', 'telegram') // КРИТИЧНО: Сначала установить loading в false, потом user // Это предотвращает бесконечную загрузку setLoading(false) setUser(userData) // Обработать параметр start из Telegram (только один раз) if (!startParamProcessed.current && tg?.startParam?.startsWith('post_')) { startParamProcessed.current = true // Пометить как обработанный const postId = tg.startParam.replace('post_', '') // Использовать navigate вместо window.location.href (не вызывает перезагрузку) // Задержка чтобы компонент успел отрендериться с user setTimeout(() => { navigate(`/feed?post=${postId}`, { replace: true }) }, 200) } return } catch (authError) { console.error('Ошибка авторизации через API:', authError) // Если авторизация не удалась, проверяем сохраненную сессию const savedUser = localStorage.getItem('nakama_user') if (savedUser) { try { const userData = JSON.parse(savedUser) // Проверить что сессия еще актуальна (можно добавить проверку времени) setUser(userData) setLoading(false) return } catch (e) { console.error('Ошибка восстановления сессии:', e) localStorage.removeItem('nakama_user') localStorage.removeItem('nakama_auth_type') } } // Если нет сохраненной сессии, показываем Login Widget setShowLogin(true) setLoading(false) return } } // Если нет initData, проверяем сохраненную сессию OAuth const savedUser = localStorage.getItem('nakama_user') const authType = localStorage.getItem('nakama_auth_type') if (savedUser && authType === 'oauth') { try { const userData = JSON.parse(savedUser) // Проверить сессию на сервере (обновить данные пользователя) try { const freshUserData = await verifySession(userData.telegramId) // Обновить сохраненную сессию localStorage.setItem('nakama_user', JSON.stringify(freshUserData)) setUser(freshUserData) } catch (sessionError) { console.error('Ошибка проверки сессии:', sessionError) // Если проверка не удалась, использовать сохраненные данные setUser(userData) } setLoading(false) return } catch (e) { console.error('Ошибка восстановления сессии:', e) localStorage.removeItem('nakama_user') localStorage.removeItem('nakama_auth_type') } } // Если нет сохраненной сессии и нет initData, показываем Login Widget setShowLogin(true) setLoading(false) } catch (err) { console.error('Ошибка инициализации:', err) setError(err.message) setLoading(false) } } const handleTelegramAuth = async (telegramUser) => { try { setLoading(true) // Отправить данные OAuth на backend const userData = await authWithTelegramOAuth(telegramUser) // Сохранить сессию для будущих загрузок localStorage.setItem('nakama_user', JSON.stringify(userData)) localStorage.setItem('nakama_auth_type', 'oauth') setUser(userData) setShowLogin(false) } catch (err) { console.error('Ошибка авторизации:', err) setError(err.message || 'Ошибка авторизации через Telegram') } finally { setLoading(false) } } if (loading) { return (

Загрузка...

) } // Показать Login Widget если нет авторизации if (showLogin) { // Получить имя бота из конфига или переменных окружения const botName = import.meta.env.VITE_TELEGRAM_BOT_NAME || 'nakama_bot' return } if (error) { return (

Ошибка загрузки приложения

{error}

) } if (!user) { return null } return ( }> } /> } /> } /> } /> } /> } /> } /> } /> ) } function App() { return ( ) } export default App