Compare commits
No commits in common. "19cdd9ab0d1595e59b78c5ee80e7e7ebb6b18ad9" and "1e48626808eed2176d3a7f96738b4f318917069f" have entirely different histories.
19cdd9ab0d
...
1e48626808
4 changed files with 10 additions and 308 deletions
|
|
@ -7,7 +7,6 @@ import Home from './pages/Home';
|
||||||
import CreateRoom from './pages/CreateRoom';
|
import CreateRoom from './pages/CreateRoom';
|
||||||
import JoinRoom from './pages/JoinRoom';
|
import JoinRoom from './pages/JoinRoom';
|
||||||
import RoomPage from './pages/RoomPage';
|
import RoomPage from './pages/RoomPage';
|
||||||
import GamePage from './pages/GamePage';
|
|
||||||
import LocalGame from './pages/LocalGame';
|
import LocalGame from './pages/LocalGame';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
|
|
@ -23,7 +22,6 @@ function App() {
|
||||||
<Route path="/create-room" element={<CreateRoom />} />
|
<Route path="/create-room" element={<CreateRoom />} />
|
||||||
<Route path="/join-room" element={<JoinRoom />} />
|
<Route path="/join-room" element={<JoinRoom />} />
|
||||||
<Route path="/room/:roomCode" element={<RoomPage />} />
|
<Route path="/room/:roomCode" element={<RoomPage />} />
|
||||||
<Route path="/game/:roomCode" element={<GamePage />} />
|
|
||||||
<Route path="/local-game" element={<LocalGame />} />
|
<Route path="/local-game" element={<LocalGame />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
.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%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,219 +0,0 @@
|
||||||
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 <div className="loading">Загрузка игры...</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<div className="error-page">
|
|
||||||
<h1>Ошибка</h1>
|
|
||||||
<p>{error}</p>
|
|
||||||
<button onClick={() => navigate('/')}>На главную</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!room) {
|
|
||||||
return (
|
|
||||||
<div className="error-page">
|
|
||||||
<h1>Комната не найдена</h1>
|
|
||||||
<button onClick={() => navigate('/')}>На главную</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isHost = user && room.hostId === user.id;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="game-page">
|
|
||||||
{isHost && (
|
|
||||||
<div className="host-controls">
|
|
||||||
<div className="pack-selector-inline">
|
|
||||||
<label>Пак вопросов:</label>
|
|
||||||
<select
|
|
||||||
value={selectedPackId}
|
|
||||||
onChange={(e) => setSelectedPackId(e.target.value)}
|
|
||||||
disabled={updatingPack}
|
|
||||||
>
|
|
||||||
<option value="">
|
|
||||||
{room.questionPackId
|
|
||||||
? 'Изменить пак вопросов'
|
|
||||||
: 'Выберите пак вопросов'}
|
|
||||||
</option>
|
|
||||||
{questionPacks.map((pack) => (
|
|
||||||
<option key={pack.id} value={pack.id}>
|
|
||||||
{pack.name} ({pack.questionCount} вопросов)
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
<button
|
|
||||||
onClick={handleUpdateQuestionPack}
|
|
||||||
disabled={
|
|
||||||
!selectedPackId ||
|
|
||||||
selectedPackId === room.questionPackId ||
|
|
||||||
updatingPack
|
|
||||||
}
|
|
||||||
className="secondary"
|
|
||||||
>
|
|
||||||
{updatingPack ? 'Сохранение...' : 'Применить'}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => navigate(`/room/${roomCode}`)}
|
|
||||||
className="secondary"
|
|
||||||
>
|
|
||||||
Назад в комнату
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="game-container">
|
|
||||||
{questions.length === 0 && (
|
|
||||||
<div className="no-questions-banner">
|
|
||||||
<p>
|
|
||||||
Вопросы не загружены.
|
|
||||||
{isHost
|
|
||||||
? ' Выберите пак вопросов выше, чтобы начать игру.'
|
|
||||||
: ' Ожидайте, пока ведущий добавит вопросы.'}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Game
|
|
||||||
questions={questions}
|
|
||||||
currentQuestionIndex={currentQuestionIndex}
|
|
||||||
onQuestionIndexChange={setCurrentQuestionIndex}
|
|
||||||
onQuestionsChange={handleQuestionsChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GamePage;
|
|
||||||
|
|
@ -100,6 +100,10 @@ const RoomPage = () => {
|
||||||
}, [room]);
|
}, [room]);
|
||||||
|
|
||||||
const handleStartGame = () => {
|
const handleStartGame = () => {
|
||||||
|
if (!room.questionPackId) {
|
||||||
|
alert('Выберите пак вопросов перед началом игры');
|
||||||
|
return;
|
||||||
|
}
|
||||||
startGame();
|
startGame();
|
||||||
navigate(`/game/${roomCode}`);
|
navigate(`/game/${roomCode}`);
|
||||||
};
|
};
|
||||||
|
|
@ -177,22 +181,21 @@ const RoomPage = () => {
|
||||||
<strong>{room.questionPack.name}</strong> (
|
<strong>{room.questionPack.name}</strong> (
|
||||||
{room.questionPack.questionCount || 0} вопросов)
|
{room.questionPack.questionCount || 0} вопросов)
|
||||||
</p>
|
</p>
|
||||||
{isHost && (
|
{isHost && room.status === 'WAITING' && (
|
||||||
<p className="pack-hint">
|
<p className="pack-hint">
|
||||||
Можете изменить пак вопросов в любой момент
|
Можете изменить пак вопросов перед началом игры
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="pack-info">
|
<div className="pack-info">
|
||||||
<p className="pack-hint">
|
<p className="pack-warning">
|
||||||
Пак вопросов не выбран. Вы можете начать игру без пака и
|
Пак вопросов не выбран. Выберите пак для начала игры.
|
||||||
добавить его позже.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isHost && (
|
{isHost && room.status === 'WAITING' && (
|
||||||
<div className="pack-selector">
|
<div className="pack-selector">
|
||||||
<select
|
<select
|
||||||
value={selectedPackId}
|
value={selectedPackId}
|
||||||
|
|
@ -232,7 +235,7 @@ const RoomPage = () => {
|
||||||
{isHost && room.status === 'WAITING' && (
|
{isHost && room.status === 'WAITING' && (
|
||||||
<button
|
<button
|
||||||
onClick={handleStartGame}
|
onClick={handleStartGame}
|
||||||
disabled={participants.length < 2}
|
disabled={participants.length < 2 || !room.questionPackId}
|
||||||
className="primary"
|
className="primary"
|
||||||
>
|
>
|
||||||
Начать игру
|
Начать игру
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue