import React, { useEffect, useState, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import { useRoom } from '../hooks/useRoom'; import { questionsApi } from '../services/api'; import QRCode from 'qrcode'; import QRModal from '../components/QRModal'; import NameInputModal from '../components/NameInputModal'; import PasswordModal from '../components/PasswordModal'; const RoomPage = () => { const { roomCode } = useParams(); const navigate = useNavigate(); const { user, loginAnonymous, loading: authLoading } = useAuth(); // Callback для автоматической навигации при старте игры const handleGameStartedEvent = useCallback(() => { navigate(`/game/${roomCode}`); }, [navigate, roomCode]); const [password, setPassword] = useState(null); const { room, participants, loading, error, requiresPassword, fetchRoomWithPassword, joinRoom, startGame, updateQuestionPack, } = useRoom(roomCode, handleGameStartedEvent, password); const [qrCode, setQrCode] = useState(''); const [joined, setJoined] = useState(false); const [isQRModalOpen, setIsQRModalOpen] = useState(false); const [isNameModalOpen, setIsNameModalOpen] = useState(false); const [isPasswordModalOpen, setIsPasswordModalOpen] = useState(false); const [passwordError, setPasswordError] = useState(null); const [questionPacks, setQuestionPacks] = useState([]); const [selectedPackId, setSelectedPackId] = useState(''); const [loadingPacks, setLoadingPacks] = useState(false); const [updatingPack, setUpdatingPack] = useState(false); useEffect(() => { const generateQR = async () => { try { // Используем абсолютный URL с протоколом для работы из любого приложения const origin = window.location.origin || `${window.location.protocol}//${window.location.host}`; const url = `${origin}/join-room?code=${roomCode}`; const qr = await QRCode.toDataURL(url, { errorCorrectionLevel: 'M', type: 'image/png', quality: 0.92, margin: 1, }); setQrCode(qr); } catch (err) { console.error('QR generation error:', err); } }; if (roomCode) { generateQR(); } }, [roomCode]); // Проверка пароля: показываем модальное окно, если требуется пароль // Хост не должен видеть модальное окно пароля (проверяется на бэкенде) useEffect(() => { if (requiresPassword && !isPasswordModalOpen && !loading && user) { // Проверяем, не является ли пользователь хостом // Если это хост, то requiresPassword не должно быть true (бэкенд должен разрешить доступ) setIsPasswordModalOpen(true); } else if (requiresPassword && !isPasswordModalOpen && !loading && !user) { // Если пользователь не авторизован, все равно показываем модальное окно // После авторизации проверим, является ли он хостом setIsPasswordModalOpen(true); } }, [requiresPassword, isPasswordModalOpen, loading, user]); // Проверка авторизации и показ модального окна для ввода имени useEffect(() => { if (!authLoading && !user && room && !loading && !requiresPassword) { setIsNameModalOpen(true); } else if (user) { setIsNameModalOpen(false); } }, [authLoading, user, room, loading, requiresPassword]); // Обработка ввода пароля const handlePasswordSubmit = async (enteredPassword) => { try { setPasswordError(null); await fetchRoomWithPassword(enteredPassword); setPassword(enteredPassword); setIsPasswordModalOpen(false); } catch (error) { console.error('Password error:', error); if (error.response?.status === 401) { setPasswordError('Неверный пароль. Попробуйте еще раз.'); } else { setPasswordError('Ошибка при проверке пароля. Попробуйте еще раз.'); } } }; // Обработка ввода имени и авторизация const handleNameSubmit = async (name) => { try { await loginAnonymous(name); setIsNameModalOpen(false); } catch (error) { console.error('Login error:', error); alert('Ошибка при авторизации. Попробуйте еще раз.'); } }; useEffect(() => { const handleJoin = async () => { if (room && user && !joined) { const isParticipant = participants.some((p) => p.userId === user.id); if (!isParticipant) { try { await joinRoom(room.id, user.id, user.name || 'Гость', 'PLAYER'); setJoined(true); } catch (error) { console.error('Join error:', error); } } else { setJoined(true); } } }; handleJoin(); }, [room, user, participants, joined, joinRoom]); useEffect(() => { const fetchPacks = async () => { if (user) { try { setLoadingPacks(true); const response = await questionsApi.getPacks(user.id); setQuestionPacks(response.data); } catch (error) { console.error('Error fetching question packs:', error); } finally { setLoadingPacks(false); } } }; if (room && user && room.hostId === user.id) { fetchPacks(); } }, [room, user]); useEffect(() => { if (room && room.questionPackId) { setSelectedPackId(room.questionPackId); } else { setSelectedPackId(''); } }, [room]); // Автоматически перенаправляем на страницу игры, если игра уже началась useEffect(() => { if (room && room.status === 'PLAYING') { navigate(`/game/${roomCode}`); } }, [room, roomCode, navigate]); const handleStartGame = () => { startGame(); navigate(`/game/${roomCode}`); }; const handleUpdateQuestionPack = async () => { if (!selectedPackId) { alert('Выберите пак вопросов'); return; } try { setUpdatingPack(true); await updateQuestionPack(selectedPackId); alert('Пак вопросов успешно добавлен'); } catch (error) { console.error('Error updating question pack:', error); alert('Ошибка при обновлении пака вопросов'); } finally { setUpdatingPack(false); } }; if (loading) { return
{error}
Статус: {room.status === 'WAITING' ? 'Ожидание игроков' : room.status}
Игроков: {participants.length}/{room.maxPlayers}
{room.questionPack.name} ( {room.questionPack.questionCount || 0} вопросов)
{isHost && (Можете изменить пак вопросов в любой момент
)}Пак вопросов не выбран. Вы можете начать игру без пака и добавить его позже.