From 45f4c143c29d46e18d8478a4301696cf4c7f6603 Mon Sep 17 00:00:00 2001 From: Anton Laktionov Date: Tue, 16 Jun 2026 13:58:33 +0300 Subject: [PATCH] fix errors --- src/App.jsx | 55 +++++--- src/components/QuizResults.css | 228 +++++++++++++++++++++++++++++++++ src/components/QuizResults.jsx | 108 ++++++++++++---- 3 files changed, 351 insertions(+), 40 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 6801982..6dfd57d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -19,7 +19,7 @@ const App = () => { const [currentAnswerResult, setCurrentAnswerResult] = useState(null); const [otherPlayersResults, setOtherPlayersResults] = useState([]); - // Новые состояния для лобби + //состояния для лобби const [showLobby, setShowLobby] = useState(true); const [currentPlayer, setCurrentPlayer] = useState(null); const [players, setPlayers] = useState([]); @@ -381,22 +381,43 @@ const App = () => { if (quizCompleted) { const score = calculateScore(); + + // Формируем массив всех игроков для таблицы лидеров const allPlayersScores = [ - { ...currentPlayer, isCurrent: true }, - ...players.filter(p => p.id !== currentPlayer.id) - ].sort((a, b) => b.score - a.score); - + { + ...currentPlayer, + isCurrent: true, + totalAnswers: userAnswers.filter(a => a && !a.timeExpired).length, + correctAnswers: userAnswers.filter(a => { + if (!a || a.timeExpired) return false; + if (a.id) { + const question = quizData.questions[userAnswers.indexOf(a)]; + return question.answers.find(ans => ans.id === a.id)?.isCorrect; + } + return false; + }).length + }, + ...players + .filter(p => p.id !== currentPlayer.id) + .map(p => ({ + ...p, + isCurrent: false, + totalAnswers: 0, // В реальном приложении здесь были бы данные + correctAnswers: 0 + })) + ].sort((a, b) => (b.score || 0) - (a.score || 0)); + return ( - + ); } @@ -466,11 +487,11 @@ const App = () => { )}
- {hasPrevious && !isTimeExpired && ( + {/*hasPrevious && !isTimeExpired && ( - )} + )*/}
); diff --git a/src/components/QuizResults.css b/src/components/QuizResults.css index 00df624..5552dc8 100644 --- a/src/components/QuizResults.css +++ b/src/components/QuizResults.css @@ -130,4 +130,232 @@ .score-number { font-size: 36px; } +} + +.leaderboard-section { + margin: 30px 0; + padding: 20px; + background: #f8f9fa; + border-radius: 15px; +} + +.leaderboard-section h3 { + color: #333; + margin-bottom: 20px; + text-align: center; + font-size: 1.3rem; +} + +.leaderboard { + display: flex; + flex-direction: column; + gap: 10px; +} + +.leaderboard-item { + display: flex; + align-items: center; + padding: 15px 20px; + background: white; + border-radius: 12px; + transition: all 0.3s ease; + border: 2px solid transparent; + gap: 15px; + box-shadow: 0 2px 8px rgba(0,0,0,0.05); +} + +.leaderboard-item:hover { + transform: translateX(5px); + box-shadow: 0 4px 15px rgba(0,0,0,0.1); +} + +.leaderboard-item.current-player { + border-color: #667eea; + background: linear-gradient(90deg, #e8eaf6 0%, #ffffff 100%); + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2); +} + +.leaderboard-item.first { + background: linear-gradient(90deg, #fff3cd 0%, #ffffff 100%); + border-color: #ffc107; +} + +.leaderboard-item.second { + background: linear-gradient(90deg, #e8e8e8 0%, #ffffff 100%); + border-color: #c0c0c0; +} + +.leaderboard-item.third { + background: linear-gradient(90deg, #ffe0b0 0%, #ffffff 100%); + border-color: #cd7f32; +} + +.leaderboard-rank { + min-width: 50px; + font-size: 1.5rem; + text-align: center; +} + +.rank-number { + display: inline-block; +} + +.leaderboard-avatar { + font-size: 2.5rem; + width: 50px; + text-align: center; +} + +.leaderboard-info { + flex: 1; + min-width: 0; +} + +.leaderboard-name { + font-weight: bold; + color: #333; + font-size: 1.1rem; + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.host-badge { + background: #ff9800; + color: white; + padding: 2px 8px; + border-radius: 12px; + font-size: 0.7rem; + font-weight: normal; +} + +.you-badge { + background: #667eea; + color: white; + padding: 2px 8px; + border-radius: 12px; + font-size: 0.7rem; + font-weight: normal; +} + +.leaderboard-stats { + display: flex; + gap: 15px; + margin-top: 4px; + flex-wrap: wrap; +} + +.stat-item { + font-size: 0.8rem; + color: #666; +} + +.leaderboard-score { + text-align: right; + min-width: 80px; +} + +.score-value { + display: block; + font-size: 1.8rem; + font-weight: bold; + color: #333; + line-height: 1; +} + +.leaderboard-item.first .score-value { + color: #ffc107; +} + +.leaderboard-item.second .score-value { + color: #c0c0c0; +} + +.leaderboard-item.third .score-value { + color: #cd7f32; +} + +.leaderboard-item.current-player .score-value { + color: #667eea; +} + +.score-label { + font-size: 0.7rem; + color: #999; + display: block; + margin-top: 2px; +} + +/* Точки за ответ */ +.points-earned { + margin-top: 5px; + color: #4caf50; + font-weight: 500; +} + +.points-earned strong { + color: #333; +} + +/* Адаптивность для таблицы лидеров */ +@media (max-width: 768px) { + .leaderboard-item { + flex-wrap: wrap; + padding: 12px 15px; + } + + .leaderboard-rank { + min-width: 35px; + font-size: 1.2rem; + } + + .leaderboard-avatar { + font-size: 2rem; + width: 40px; + } + + .leaderboard-info { + width: 100%; + order: 3; + margin-top: 5px; + } + + .leaderboard-score { + margin-left: auto; + min-width: 60px; + } + + .score-value { + font-size: 1.4rem; + } + + .leaderboard-stats { + font-size: 0.7rem; + gap: 10px; + } +} + +/* Анимация появления */ +.leaderboard-item { + animation: slideInLeft 0.5s ease forwards; + opacity: 0; +} + +.leaderboard-item:nth-child(1) { animation-delay: 0.1s; } +.leaderboard-item:nth-child(2) { animation-delay: 0.2s; } +.leaderboard-item:nth-child(3) { animation-delay: 0.3s; } +.leaderboard-item:nth-child(4) { animation-delay: 0.4s; } +.leaderboard-item:nth-child(5) { animation-delay: 0.5s; } +.leaderboard-item:nth-child(6) { animation-delay: 0.6s; } + +@keyframes slideInLeft { + from { + opacity: 0; + transform: translateX(-20px); + } + to { + opacity: 1; + transform: translateX(0); + } } \ No newline at end of file diff --git a/src/components/QuizResults.jsx b/src/components/QuizResults.jsx index 9185cfa..cc579d0 100644 --- a/src/components/QuizResults.jsx +++ b/src/components/QuizResults.jsx @@ -1,7 +1,16 @@ import React from 'react'; import './QuizResults.css'; -const QuizResults = ({ score, totalQuestions, userAnswers, quizData, onRestart, timeExpiredQuestions }) => { +const QuizResults = ({ + score, + totalQuestions, + userAnswers, + quizData, + onRestart, + timeExpiredQuestions, + allPlayers = [], // Добавляем allPlayers с значением по умолчанию + currentPlayer = null +}) => { const percentage = (score / totalQuestions) * 100; let resultMessage = ""; @@ -42,7 +51,7 @@ const QuizResults = ({ score, totalQuestions, userAnswers, quizData, onRestart, }; const getAnswerStatus = (question, answer, index) => { - if (timeExpiredQuestions.includes(index)) { + if (timeExpiredQuestions?.includes(index)) { return "expired"; } if (question.type === "single" && answer && !answer.timeExpired) { @@ -55,11 +64,28 @@ const QuizResults = ({ score, totalQuestions, userAnswers, quizData, onRestart, return "unanswered"; }; + // Функция для получения эмодзи медали + const getMedalEmoji = (index) => { + if (index === 0) return "🥇"; + if (index === 1) return "🥈"; + if (index === 2) return "🥉"; + return `#${index + 1}`; + }; + + // Функция для получения класса места + const getRankClass = (index) => { + if (index === 0) return "first"; + if (index === 1) return "second"; + if (index === 2) return "third"; + return "other"; + }; + return (
-

Ваши результаты

+

🏆 Результаты викторины

+ {/* Основной результат */}
{score}
/{totalQuestions}
@@ -68,17 +94,62 @@ const QuizResults = ({ score, totalQuestions, userAnswers, quizData, onRestart,

{resultMessage}

Правильных ответов: {Math.round(percentage)}%

- {timeExpiredQuestions.length > 0 && ( + {timeExpiredQuestions?.length > 0 && (

⚠️ На {timeExpiredQuestions.length} вопрос{(timeExpiredQuestions.length > 1 ? 'ах' : 'е')} время истекло

)} + {currentPlayer && ( +

+ 🎯 Всего очков: {currentPlayer.score || 0} +

+ )}
- + + {/* Таблица лидеров */} + {allPlayers && allPlayers.length > 0 && ( +
+

👑 Таблица лидеров

+
+ {allPlayers.map((player, index) => ( +
+
+ {getMedalEmoji(index)} +
+
{player.avatar || "👤"}
+
+
+ {player.name || "Игрок"} + {player.isHost && 👑 Хост} + {player.isCurrent && Вы} +
+
+ + ⭐ {player.correctAnswers || 0} правильных + + + 📝 {player.totalAnswers || 0} ответов + +
+
+
+ {player.score || 0} + очков +
+
+ ))} +
+
+ )} + + {/* Обзор ответов */}
-

Обзор ответов:

- {quizData.questions.map((question, index) => { - const userAnswer = userAnswers[index]; +

📋 Обзор ваших ответов:

+ {quizData && quizData.questions && quizData.questions.map((question, index) => { + const userAnswer = userAnswers?.[index]; const status = getAnswerStatus(question, userAnswer, index); return ( @@ -94,7 +165,7 @@ const QuizResults = ({ score, totalQuestions, userAnswers, quizData, onRestart,
Ваш ответ: {getUserAnswerText(question, userAnswer, index)}
- {status !== "expired" && status !== "pending" && ( + {status !== "expired" && status !== "pending" && status !== "unanswered" && (
Правильный ответ: {getCorrectAnswerText(question, index)}
@@ -104,25 +175,16 @@ const QuizResults = ({ score, totalQuestions, userAnswers, quizData, onRestart, ⏱️ Время на ответ: {userAnswer.timeSpent} сек
)} + {userAnswer?.pointsEarned > 0 && ( +
+ 🎯 Очков получено: +{userAnswer.pointsEarned} +
+ )}
); })}
-
-

🏆 Итоговая таблица лидеров

- {allPlayers.map((player, index) => ( -
-
{index + 1}
-
{player.avatar}
-
- {player.name} - {player.isCurrent && (Вы)} -
-
{player.score} очков
-
- ))} -