diff --git a/client/src/components/GameBoard.jsx b/client/src/components/GameBoard.jsx index e8802fc..d46a9a0 100644 --- a/client/src/components/GameBoard.jsx +++ b/client/src/components/GameBoard.jsx @@ -1,33 +1,20 @@ function GameBoard({ questions, usedQuestions, onSelectQuestion, currentRound, isHost }) { const isQuestionUsed = (category, points, questionIndex) => { - // Ищем этот конкретный вопрос в использованных - // Сначала проверяем по questionIndex (новый метод) const foundByIndex = usedQuestions.find( q => q.category === category && q.points === points && q.questionIndex === questionIndex ); + if (foundByIndex) return true; - if (foundByIndex) { - console.log(`✓ Question used (by index): cat="${category}", pts=${points}, idx=${questionIndex}`); - return true; - } - - // Для обратной совместимости: если в usedQuestions нет questionIndex, - // проверяем, сколько вопросов с такими баллами уже использовано const usedCount = usedQuestions.filter( q => q.category === category && q.points === points ).length; - if (usedCount === 0) return false; - // Получаем категорию и находим индекс вопроса среди вопросов с такими же баллами const categoryData = questions.find(cat => cat.name === category); const questionsWithSamePoints = categoryData?.questions .map((q, idx) => ({ ...q, originalIndex: idx })) .filter(q => q.points === points) || []; - const positionAmongSamePoints = questionsWithSamePoints.findIndex(q => q.originalIndex === questionIndex); - - // Если позиция вопроса меньше количества использованных, значит он уже использован return positionAmongSamePoints >= 0 && positionAmongSamePoints < usedCount; } @@ -35,15 +22,12 @@ function GameBoard({ questions, usedQuestions, onSelectQuestion, currentRound, i return round === 2 ? basePoints * 2 : basePoints } - // Проверить сколько вопросов осталось в категории const hasAvailableQuestions = (category) => { return category.questions.some((q, idx) => !isQuestionUsed(category.name, q.points, idx)) } - // Фильтруем категории - показываем только те, где есть доступные вопросы const availableCategories = questions.filter(hasAvailableQuestions) - // Лог для отладки console.log('📋 GameBoard render:', { totalCategories: questions.length, availableCategories: availableCategories.length, @@ -51,35 +35,35 @@ function GameBoard({ questions, usedQuestions, onSelectQuestion, currentRound, i }); return ( -
+
{!isHost && ( -
-

- Ведущий выбирает вопросы. Будьте готовы отвечать! +

+

+ 🎯 Ведущий выбирает вопросы. Будьте готовы!

)} {isHost && ( -
-

- Выберите вопрос +

+

+ 👆 Выберите вопрос

)} {availableCategories.length > 0 ? ( -
+
{availableCategories.map((category, catIdx) => ( -
- {/* Название категории */} -
-

+
+ {/* Category name */} +
+

{category.name}

- {/* Вопросы по номиналам */} -
+ {/* Question buttons */} +
{category.questions.map((question, questionIndex) => { const displayPoints = getPointsForRound(question.points, currentRound) const isUsed = isQuestionUsed(category.name, question.points, questionIndex) @@ -89,12 +73,12 @@ function GameBoard({ questions, usedQuestions, onSelectQuestion, currentRound, i key={questionIndex} onClick={() => !isUsed && isHost && onSelectQuestion(category.name, question.points)} disabled={isUsed || !isHost} - className={`flex-1 p-3 md:p-6 rounded-lg font-bold text-base md:text-2xl transition-all duration-200 ${ + className={`flex-1 p-3 md:p-5 rounded-xl font-bold text-base md:text-xl transition-all duration-300 ${ isUsed - ? 'bg-slate-700 text-gray-500 cursor-not-allowed border border-slate-600' + ? 'bg-white/3 text-gray-600 cursor-not-allowed border border-white/5' : isHost - ? 'bg-blue-600 text-white hover:bg-blue-700 cursor-pointer shadow-lg border border-blue-500' - : 'bg-blue-600 text-white cursor-default opacity-60 border border-blue-500' + ? 'bg-gradient-to-br from-blue-600/60 to-indigo-700/60 text-white hover:from-blue-500/80 hover:to-indigo-600/80 cursor-pointer shadow-lg hover:shadow-blue-500/20 border border-blue-400/20 hover:border-blue-400/40 hover:scale-105 active:scale-95 backdrop-blur-sm' + : 'bg-gradient-to-br from-blue-600/40 to-indigo-700/40 text-white/70 cursor-default border border-blue-400/10 backdrop-blur-sm' }`} > {isUsed ? '—' : displayPoints} @@ -106,9 +90,9 @@ function GameBoard({ questions, usedQuestions, onSelectQuestion, currentRound, i ))}
) : ( -
+

- Все вопросы раунда {currentRound} использованы! + ✅ Все вопросы раунда {currentRound} использованы!

)} diff --git a/client/src/components/QuestionModal.jsx b/client/src/components/QuestionModal.jsx index ebbe35b..555af60 100644 --- a/client/src/components/QuestionModal.jsx +++ b/client/src/components/QuestionModal.jsx @@ -8,226 +8,175 @@ function QuestionModal({ question, timer, onSubmitAnswer, answeringTeamName, isH if (!question) return null - // Обработчик окончания проигрывания медиа const handleMediaEnded = () => { console.log('🎬 Media playback ended'); setMediaEnded(true); - - // Отправляем событие на сервер, чтобы начался таймер if (socket && gameCode) { socket.emit('media-ended', { gameCode }); } } - // Сбрасываем флаг при смене вопроса useEffect(() => { setMediaEnded(false); }, [question]) const getMediaUrl = (path) => { - // Если определена переменная окружения, используем её - if (import.meta.env.VITE_SERVER_URL) { - return `${import.meta.env.VITE_SERVER_URL}${path}` - } - - // В production используем текущий хост (Caddy проксирует на сервер) - if (import.meta.env.PROD) { - return `${window.location.protocol}//${window.location.host}${path}` - } - - // В development используем localhost + if (import.meta.env.VITE_SERVER_URL) return `${import.meta.env.VITE_SERVER_URL}${path}` + if (import.meta.env.PROD) return `${window.location.protocol}//${window.location.host}${path}` return `http://localhost:3001${path}` } + const timerColor = timer !== null + ? timer <= 5 ? 'text-red-400' : timer <= 10 ? 'text-amber-400' : 'text-white' + : 'text-white' + + const timerBg = timer !== null && timer <= 5 ? 'animate-pulse' : '' + const renderQuestionContent = () => { + const wrapperClass = "bg-gradient-to-br from-indigo-900/40 to-purple-900/40 border border-indigo-400/20 p-4 md:p-8 rounded-xl mb-4 md:mb-6 backdrop-blur-sm" + switch (question.type) { case 'image': return ( -
- Question +
+ Question {question.questionText && ( -

- {question.questionText} -

+

{question.questionText}

)}
) - case 'audio': return ( -
-