From 01f1e1ae9465c340d36b13ed7a56a7dfaba3e85e Mon Sep 17 00:00:00 2001 From: glpshchn <464976@niuitmo.ru> Date: Mon, 1 Dec 2025 08:40:27 +0300 Subject: [PATCH] Update files --- EMPTY_SCREEN_FIX.md | 156 ++++++++++++++++++++++ backend/routes/posts.js | 5 +- frontend/src/App.jsx | 57 +++++++- frontend/src/components/CommentsModal.jsx | 24 ++-- frontend/src/components/PostCard.jsx | 38 ++++-- frontend/src/pages/CommentsPage.jsx | 26 ++-- frontend/src/pages/Feed.jsx | 7 +- frontend/src/pages/PostMenuPage.jsx | 11 +- frontend/src/utils/api.js | 25 +++- 9 files changed, 305 insertions(+), 44 deletions(-) create mode 100644 EMPTY_SCREEN_FIX.md diff --git a/EMPTY_SCREEN_FIX.md b/EMPTY_SCREEN_FIX.md new file mode 100644 index 0000000..b2296ad --- /dev/null +++ b/EMPTY_SCREEN_FIX.md @@ -0,0 +1,156 @@ +# Исправление: Пустой экран после верификации + +## 🔴 Проблема +После успешной верификации UI открывается, но моментально пропадает (полностью пустой экран). + +--- + +## ✅ Что исправлено + +### 1. **Улучшена обработка ошибок** +- Добавлено подробное логирование в консоль браузера +- Теперь видно, на каком этапе происходит ошибка + +### 2. **Исправлен пустой экран** +- Вместо `return null` теперь показывается сообщение с кнопкой перезагрузки +- Это помогает понять, что происходит + +### 3. **Отложен запуск initDataChecker** +- `initDataChecker` теперь запускается только после успешной загрузки пользователя +- Это предотвращает преждевременную перезагрузку страницы + +### 4. **Улучшена валидация данных** +- Проверяется, что `userData` действительно получен +- Если `null` или `undefined` - показывается ошибка + +--- + +## 🔍 Как диагностировать + +### Шаг 1: Откройте консоль браузера + +1. В Telegram откройте приложение +2. Нажмите **F12** или **Cmd+Option+I** (Mac) +3. Перейдите на вкладку **Console** + +### Шаг 2: Посмотрите логи + +**Должны увидеть:** +``` +[App] Начало инициализации... +[App] Telegram WebApp найден, initData: есть +[API] verifyAuth: отправка запроса... +[API] verifyAuth: получен ответ: { hasUser: true, userId: "...", username: "..." } +[App] verifyAuth вернул: данные пользователя +[App] Пользователь установлен, ID: ... +[App] Инициализация завершена, loading: false +``` + +**Если видите ошибку:** +``` +[API] verifyAuth: ошибка: { message: "...", status: 401/500 } +[App] Ошибка инициализации: ... +``` + +--- + +## 🐛 Возможные причины + +### 1. **Ошибка 401 (Unauthorized)** +**Причина:** `initData` невалиден или истек + +**Решение:** +- Перезагрузите приложение в Telegram +- Убедитесь, что используете официальный клиент Telegram + +### 2. **Ошибка 500 (Server Error)** +**Причина:** Проблема на backend + +**Решение:** +```bash +# Проверьте логи backend +docker logs nakama-backend --tail 100 + +# Ищите ошибки: +# - "Ошибка verify" +# - "MongoDB connection" +# - "MinIO connection" +``` + +### 3. **userData = null/undefined** +**Причина:** Backend не вернул данные пользователя + +**Решение:** +- Проверьте маршрут `/api/auth/verify` на backend +- Убедитесь, что пользователь существует в БД +- Проверьте, что `respondWithUser` работает правильно + +### 4. **Ошибка в компонентах Feed/Layout** +**Причина:** Компонент падает при рендеринге + +**Решение:** +- В консоли браузера будет **красная ошибка** с указанием файла и строки +- Проверьте, что все данные пользователя присутствуют (`user.settings`, `user.photoUrl`, etc.) + +--- + +## 🔧 Быстрое решение + +### 1. Перезагрузите приложение +```javascript +// В консоли браузера +window.location.reload() +``` + +### 2. Проверьте backend +```bash +# Проверьте, что backend работает +curl http://your-backend-url/api/health + +# Проверьте логи +docker logs nakama-backend -f +``` + +### 3. Проверьте MongoDB +```bash +# Подключитесь к MongoDB +docker exec -it nakama-mongodb mongosh + +# Проверьте пользователей +use nakama +db.users.find().limit(5) +``` + +--- + +## 📋 Контрольный список + +- [ ] Консоль браузера открыта (F12) +- [ ] Видны логи `[App]` и `[API]` +- [ ] Нет красных ошибок в консоли +- [ ] Backend доступен (`/api/health`) +- [ ] MongoDB подключена +- [ ] Пользователь существует в БД +- [ ] `initData` валиден (не истек) + +--- + +## 💡 Если все еще не работает + +### Отправьте мне: +1. **Логи из консоли браузера** (скопируйте все сообщения) +2. **Логи backend** (`docker logs nakama-backend --tail 200`) +3. **Скриншот пустого экрана** +4. **Ошибки из консоли** (красные сообщения) + +--- + +## ✅ После исправления + +После применения исправлений вы должны видеть: +- ✅ Логи в консоли на каждом этапе +- ✅ Сообщение об ошибке вместо пустого экрана +- ✅ Кнопку "Перезагрузить" если что-то пошло не так + +**Теперь откройте приложение и посмотрите консоль браузера!** 🔍 + diff --git a/backend/routes/posts.js b/backend/routes/posts.js index 8fd3ff6..66e87fe 100644 --- a/backend/routes/posts.js +++ b/backend/routes/posts.js @@ -39,7 +39,7 @@ router.get('/', authenticate, async (req, res) => { query.isNSFW = false; } - const posts = await Post.find(query) + let posts = await Post.find(query) .populate('author', 'username firstName lastName photoUrl') .populate('mentionedUsers', 'username firstName lastName') .populate('comments.author', 'username firstName lastName photoUrl') @@ -48,6 +48,9 @@ router.get('/', authenticate, async (req, res) => { .skip((page - 1) * limit) .exec(); + // Фильтруем посты без автора (защита от ошибок) + posts = posts.filter(post => post.author !== null && post.author !== undefined); + const count = await Post.countDocuments(query); res.json({ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1547602..f0e1476 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -30,8 +30,7 @@ function AppContent() { initApp() } - // Запустить проверку initData - startInitDataChecker() + // НЕ запускать initDataChecker здесь - он запустится после успешной загрузки пользователя return () => { stopInitDataChecker() @@ -40,6 +39,7 @@ function AppContent() { const initApp = async () => { try { + console.log('[App] Начало инициализации...') initTelegramApp() const tg = window.Telegram?.WebApp @@ -52,12 +52,25 @@ function AppContent() { throw new Error('Telegram не передал initData. Откройте приложение из официального клиента.') } + console.log('[App] Telegram WebApp найден, initData:', tg.initData ? 'есть' : 'нет') + tg.disableVerticalSwipes?.() tg.expand?.() + console.log('[App] Вызов verifyAuth...') const userData = await verifyAuth() + console.log('[App] verifyAuth вернул:', userData ? 'данные пользователя' : 'null/undefined', userData) + + if (!userData) { + throw new Error('Не удалось получить данные пользователя. Попробуйте перезагрузить страницу.') + } + setUser(userData) setError(null) + console.log('[App] Пользователь установлен, ID:', userData.id || userData._id) + + // Запустить проверку initData только после успешной загрузки + startInitDataChecker() if (!startParamProcessed.current && tg?.startParam?.startsWith('post_')) { startParamProcessed.current = true @@ -67,10 +80,17 @@ function AppContent() { }, 200) } } catch (err) { - console.error('Ошибка инициализации:', err) + console.error('[App] Ошибка инициализации:', err) + console.error('[App] Детали ошибки:', { + message: err.message, + response: err.response?.data, + status: err.response?.status + }) setError(err?.response?.data?.error || err.message || 'Ошибка авторизации') + setUser(null) // Явно сбросить user при ошибке } finally { setLoading(false) + console.log('[App] Инициализация завершена, loading:', false) } } @@ -126,7 +146,36 @@ function AppContent() { } if (!user) { - return null + // Показываем сообщение вместо пустого экрана + return ( +
+

+ Загрузка данных пользователя... +

+ +
+ ) } return ( diff --git a/frontend/src/components/CommentsModal.jsx b/frontend/src/components/CommentsModal.jsx index 22f4751..fb8846f 100644 --- a/frontend/src/components/CommentsModal.jsx +++ b/frontend/src/components/CommentsModal.jsx @@ -64,16 +64,17 @@ export default function CommentsModal({ post, onClose, onUpdate }) {
{post.author.username { e.target.src = '/default-avatar.png' }} />
- {post.author.firstName || ''} {post.author.lastName || ''} - {!post.author.firstName && !post.author.lastName && 'Пользователь'} + {post.author?.firstName || ''} {post.author?.lastName || ''} + {!post.author?.firstName && !post.author?.lastName && 'Пользователь'}
-
@{post.author.username || post.author.firstName || 'user'}
+
@{post.author?.username || post.author?.firstName || 'user'}
@@ -96,18 +97,21 @@ export default function CommentsModal({ post, onClose, onUpdate }) { Будьте первым!
) : ( - comments.map((c, index) => ( + comments + .filter(c => c.author) // Фильтруем комментарии без автора + .map((c, index) => (
{c.author.username { e.target.src = '/default-avatar.png' }} />
- {c.author.firstName || ''} {c.author.lastName || ''} - {!c.author.firstName && !c.author.lastName && 'Пользователь'} + {c.author?.firstName || ''} {c.author?.lastName || ''} + {!c.author?.firstName && !c.author?.lastName && 'Пользователь'} {formatDate(c.createdAt)}
diff --git a/frontend/src/components/PostCard.jsx b/frontend/src/components/PostCard.jsx index 016d5f4..4ef4dad 100644 --- a/frontend/src/components/PostCard.jsx +++ b/frontend/src/components/PostCard.jsx @@ -19,13 +19,28 @@ const TAG_NAMES = { export default function PostCard({ post, currentUser, onUpdate }) { const navigate = useNavigate() - const [liked, setLiked] = useState(post.likes.includes(currentUser.id)) - const [likesCount, setLikesCount] = useState(post.likes.length) + const [liked, setLiked] = useState(post.likes?.includes(currentUser.id) || false) + const [likesCount, setLikesCount] = useState(post.likes?.length || 0) const [currentImageIndex, setCurrentImageIndex] = useState(0) const [showFullView, setShowFullView] = useState(false) + // Проверка на существование автора + if (!post.author) { + console.warn('[PostCard] Post without author:', post._id) + return null // Не показываем посты без автора + } + // Поддержка и старого поля imageUrl и нового images - const images = post.images && post.images.length > 0 ? post.images : (post.imageUrl ? [post.imageUrl] : []) + // Фильтруем старые URL из Telegram API + const allImages = post.images && post.images.length > 0 ? post.images : (post.imageUrl ? [post.imageUrl] : []) + const images = allImages.filter(img => { + // Игнорируем старые URL из Telegram API + if (img && typeof img === 'string' && img.includes('api.telegram.org/file/bot')) { + console.warn('[PostCard] Skipping old Telegram URL:', img) + return false + } + return true + }) const handleLike = async () => { try { @@ -61,7 +76,9 @@ export default function PostCard({ post, currentUser, onUpdate }) { } const goToProfile = () => { - navigate(`/user/${post.author._id}`) + if (post.author?._id) { + navigate(`/user/${post.author._id}`) + } } const openFullView = () => { @@ -103,17 +120,20 @@ export default function PostCard({ post, currentUser, onUpdate }) {
{post.author.username { + e.target.src = '/default-avatar.png' + }} />
- {post.author.firstName || ''} {post.author.lastName || ''} - {!post.author.firstName && !post.author.lastName && 'Пользователь'} + {post.author?.firstName || ''} {post.author?.lastName || ''} + {!post.author?.firstName && !post.author?.lastName && 'Пользователь'}
- @{post.author.username || post.author.firstName || 'user'} · {formatDate(post.createdAt)} + @{post.author?.username || post.author?.firstName || 'user'} · {formatDate(post.createdAt)}
diff --git a/frontend/src/pages/CommentsPage.jsx b/frontend/src/pages/CommentsPage.jsx index e574373..9f227f9 100644 --- a/frontend/src/pages/CommentsPage.jsx +++ b/frontend/src/pages/CommentsPage.jsx @@ -122,16 +122,17 @@ export default function CommentsPage({ user }) {
{post.author.username { e.target.src = '/default-avatar.png' }} />
- {post.author.firstName || ''} {post.author.lastName || ''} - {!post.author.firstName && !post.author.lastName && 'Пользователь'} + {post.author?.firstName || ''} {post.author?.lastName || ''} + {!post.author?.firstName && !post.author?.lastName && 'Пользователь'}
-
@{post.author.username || post.author.firstName || 'user'}
+
@{post.author?.username || post.author?.firstName || 'user'}
@@ -156,23 +157,26 @@ export default function CommentsPage({ user }) { Будьте первым!
) : ( - comments.map((c, index) => { + comments + .filter(c => c.author) // Фильтруем комментарии без автора + .map((c, index) => { const isEditing = editingCommentId === c._id - const isOwnComment = c.author._id === user.id + const isOwnComment = c.author?._id === user.id const canEdit = isOwnComment || user.role === 'moderator' || user.role === 'admin' return (
{c.author.username { e.target.src = '/default-avatar.png' }} />
- {c.author.firstName || ''} {c.author.lastName || ''} - {!c.author.firstName && !c.author.lastName && 'Пользователь'} + {c.author?.firstName || ''} {c.author?.lastName || ''} + {!c.author?.firstName && !c.author?.lastName && 'Пользователь'} {formatDate(c.createdAt)} diff --git a/frontend/src/pages/Feed.jsx b/frontend/src/pages/Feed.jsx index bd248b2..e5db88a 100644 --- a/frontend/src/pages/Feed.jsx +++ b/frontend/src/pages/Feed.jsx @@ -71,10 +71,13 @@ export default function Feed({ user }) { const data = await getPosts(params) + // Фильтруем посты без автора (защита от ошибок) + const validPosts = data.posts.filter(post => post.author) + if (pageNum === 1) { - setPosts(data.posts) + setPosts(validPosts) } else { - setPosts(prev => [...prev, ...data.posts]) + setPosts(prev => [...prev, ...validPosts]) } setHasMore(pageNum < data.totalPages) diff --git a/frontend/src/pages/PostMenuPage.jsx b/frontend/src/pages/PostMenuPage.jsx index 0f795fd..d6700a7 100644 --- a/frontend/src/pages/PostMenuPage.jsx +++ b/frontend/src/pages/PostMenuPage.jsx @@ -188,16 +188,17 @@ export default function PostMenuPage({ user }) {
{post.author.username { e.target.src = '/default-avatar.png' }} />
- {post.author.firstName || ''} {post.author.lastName || ''} - {!post.author.firstName && !post.author.lastName && 'Пользователь'} + {post.author?.firstName || ''} {post.author?.lastName || ''} + {!post.author?.firstName && !post.author?.lastName && 'Пользователь'}
-
@{post.author.username || post.author.firstName || 'user'}
+
@{post.author?.username || post.author?.firstName || 'user'}
diff --git a/frontend/src/utils/api.js b/frontend/src/utils/api.js index 89e2646..ca674b1 100644 --- a/frontend/src/utils/api.js +++ b/frontend/src/utils/api.js @@ -79,8 +79,29 @@ export const signInWithTelegram = async (initData) => { } export const verifyAuth = async () => { - const response = await api.post('/auth/verify') - return response.data.user + try { + console.log('[API] verifyAuth: отправка запроса...') + const response = await api.post('/auth/verify') + console.log('[API] verifyAuth: получен ответ:', { + hasUser: !!response.data?.user, + userId: response.data?.user?.id || response.data?.user?._id, + username: response.data?.user?.username + }) + + if (!response.data?.user) { + console.error('[API] verifyAuth: ответ не содержит user:', response.data) + throw new Error('Сервер не вернул данные пользователя') + } + + return response.data.user + } catch (error) { + console.error('[API] verifyAuth: ошибка:', { + message: error.message, + response: error.response?.data, + status: error.response?.status + }) + throw error + } } // Авторизация через Telegram OAuth (Login Widget)