From 19cdd9ab0d1595e59b78c5ee80e7e7ebb6b18ad9 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Tue, 6 Jan 2026 23:46:49 +0300 Subject: [PATCH] ref --- src/pages/GamePage.css | 80 +++++++++++++++ src/pages/GamePage.jsx | 219 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 src/pages/GamePage.css create mode 100644 src/pages/GamePage.jsx diff --git a/src/pages/GamePage.css b/src/pages/GamePage.css new file mode 100644 index 0000000..568592b --- /dev/null +++ b/src/pages/GamePage.css @@ -0,0 +1,80 @@ +.game-page { + min-height: 100vh; + display: flex; + flex-direction: column; +} + +.host-controls { + background: var(--bg-secondary, #f5f5f5); + padding: 1rem; + border-bottom: 1px solid var(--border-color, #ddd); +} + +.pack-selector-inline { + display: flex; + gap: 1rem; + align-items: center; + flex-wrap: wrap; +} + +.pack-selector-inline label { + font-weight: 500; +} + +.pack-selector-inline select { + flex: 1; + min-width: 200px; + padding: 0.5rem; + border: 1px solid var(--border-color, #ddd); + border-radius: 4px; + font-size: 1rem; +} + +.pack-selector-inline button { + padding: 0.5rem 1rem; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 1rem; + white-space: nowrap; +} + +.pack-selector-inline button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.game-container { + flex: 1; + display: flex; + flex-direction: column; +} + +.no-questions-banner { + text-align: center; + padding: 2rem; + background: var(--bg-secondary, #f5f5f5); + border-radius: 8px; + margin: 2rem; +} + +.no-questions-banner p { + font-size: 1.2rem; + color: var(--text-secondary, #666); + margin-bottom: 1rem; +} + +@media (max-width: 768px) { + .pack-selector-inline { + flex-direction: column; + align-items: stretch; + } + + .pack-selector-inline select { + width: 100%; + } + + .pack-selector-inline button { + width: 100%; + } +} diff --git a/src/pages/GamePage.jsx b/src/pages/GamePage.jsx new file mode 100644 index 0000000..40099a7 --- /dev/null +++ b/src/pages/GamePage.jsx @@ -0,0 +1,219 @@ +import React, { useEffect, useState } 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 Game from '../components/Game'; +import './GamePage.css'; + +const GamePage = () => { + const { roomCode } = useParams(); + const navigate = useNavigate(); + const { user } = useAuth(); + const { + room, + participants, + loading, + error, + updateQuestionPack, + } = useRoom(roomCode); + + const [questions, setQuestions] = useState([]); + const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); + const [loadingQuestions, setLoadingQuestions] = useState(true); + const [questionPacks, setQuestionPacks] = useState([]); + const [selectedPackId, setSelectedPackId] = useState(''); + const [updatingPack, setUpdatingPack] = useState(false); + + useEffect(() => { + const loadQuestions = async () => { + if (!room) return; + + setLoadingQuestions(true); + try { + if (room.questionPackId) { + // Загружаем вопросы из пака + if (room.questionPack && room.questionPack.questions) { + const packQuestions = room.questionPack.questions; + if (Array.isArray(packQuestions)) { + setQuestions(packQuestions); + } else { + setQuestions([]); + } + } else { + // Загружаем пак отдельно, если он не включен в room + const response = await questionsApi.getPack(room.questionPackId); + if (response.data && response.data.questions) { + setQuestions( + Array.isArray(response.data.questions) + ? response.data.questions + : [], + ); + } else { + setQuestions([]); + } + } + } else { + // Пак не выбран, начинаем с пустого списка вопросов + setQuestions([]); + } + } catch (error) { + console.error('Error loading questions:', error); + setQuestions([]); + } finally { + setLoadingQuestions(false); + } + }; + + loadQuestions(); + }, [room]); + + useEffect(() => { + const fetchPacks = async () => { + if (user && room && room.hostId === user.id) { + try { + const response = await questionsApi.getPacks(user.id); + setQuestionPacks(response.data); + } catch (error) { + console.error('Error fetching question packs:', error); + } + } + }; + + fetchPacks(); + }, [user, room]); + + useEffect(() => { + if (room && room.questionPackId) { + setSelectedPackId(room.questionPackId); + } else { + setSelectedPackId(''); + } + }, [room]); + + const handleUpdateQuestionPack = async () => { + if (!selectedPackId) { + alert('Выберите пак вопросов'); + return; + } + + try { + setUpdatingPack(true); + await updateQuestionPack(selectedPackId); + // Перезагружаем вопросы после обновления пака + const response = await questionsApi.getPack(selectedPackId); + if (response.data && response.data.questions) { + setQuestions( + Array.isArray(response.data.questions) + ? response.data.questions + : [], + ); + setCurrentQuestionIndex(0); + } + } catch (error) { + console.error('Error updating question pack:', error); + alert('Ошибка при обновлении пака вопросов'); + } finally { + setUpdatingPack(false); + } + }; + + const handleQuestionsChange = (newQuestions) => { + setQuestions(newQuestions); + if (currentQuestionIndex >= newQuestions.length) { + setCurrentQuestionIndex(0); + } + }; + + if (loading || loadingQuestions) { + return
Загрузка игры...
; + } + + if (error) { + return ( +
+

Ошибка

+

{error}

+ +
+ ); + } + + if (!room) { + return ( +
+

Комната не найдена

+ +
+ ); + } + + const isHost = user && room.hostId === user.id; + + return ( +
+ {isHost && ( +
+
+ + + + +
+
+ )} + +
+ {questions.length === 0 && ( +
+

+ Вопросы не загружены. + {isHost + ? ' Выберите пак вопросов выше, чтобы начать игру.' + : ' Ожидайте, пока ведущий добавит вопросы.'} +

+
+ )} + + +
+
+ ); +}; + +export default GamePage;