This commit is contained in:
Dmitry 2026-01-11 00:55:55 +03:00
parent 625c5837ee
commit 35c5fb8cd8
5 changed files with 55 additions and 18 deletions

View file

@ -305,7 +305,14 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect, On
const isHost = await this.isHost(payload.roomId, payload.userId);
const isCurrentPlayer = room.currentPlayerId === payload.participantId;
if (!isHost && !isCurrentPlayer) {
// Только хост может открывать ответы
if (payload.action === 'revealAnswer' && !isHost) {
client.emit('error', { message: 'Only the host can reveal answers' });
return;
}
// Для других действий проверяем права (хост или текущий игрок)
if (payload.action !== 'revealAnswer' && !isHost && !isCurrentPlayer) {
client.emit('error', { message: 'Not your turn!' });
return;
}

View file

@ -72,6 +72,8 @@ export class RoomsService {
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
@ -133,12 +135,14 @@ export class RoomsService {
},
});
// Получаем обновленную комнату со всеми участниками
// Получаем обновленную комнату со всеми активными участниками
const updatedRoom = await this.prisma.room.findUnique({
where: { id: roomId },
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
@ -221,12 +225,14 @@ export class RoomsService {
},
});
// Получаем обновленную комнату со всеми участниками
// Получаем обновленную комнату со всеми активными участниками
const updatedRoom = await this.prisma.room.findUnique({
where: { id: roomId },
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
@ -291,6 +297,8 @@ export class RoomsService {
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
@ -320,6 +328,8 @@ export class RoomsService {
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
@ -367,6 +377,8 @@ export class RoomsService {
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
@ -404,9 +416,13 @@ export class RoomsService {
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
roomPack: true,
theme: true,
},
});
@ -424,9 +440,13 @@ export class RoomsService {
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
roomPack: true,
theme: true,
},
});
@ -445,6 +465,8 @@ export class RoomsService {
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,
@ -537,12 +559,14 @@ export class RoomsService {
data: { role: newRole },
});
// Получаем обновленную комнату со всеми участниками
// Получаем обновленную комнату со всеми активными участниками
const room = await this.prisma.room.findUnique({
where: { id: roomId },
include: {
host: true,
participants: {
where: { isActive: true },
orderBy: { joinedAt: 'asc' },
include: { user: true },
},
questionPack: true,

View file

@ -3,8 +3,8 @@
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
overflow: visible;
}
.question-box {
@ -130,8 +130,9 @@
grid-auto-rows: minmax(auto, clamp(120px, 18vh, 200px));
column-gap: clamp(6px, 1.2vw, 12px);
row-gap: clamp(6px, 0.8vh, 12px);
flex: 1 1 0;
flex: 0 1 auto;
min-height: 0;
max-height: 100%;
overflow-y: auto;
align-content: start;
/* Scrollbar styling */

View file

@ -175,20 +175,13 @@ const GamePage = () => {
// === Handlers для действий игрока ===
const handleAnswerClick = (answerId, points) => {
if (!gameState.roomId || !user || !canPerformActions) return;
if (!gameState.roomId || !user) return;
const myParticipant = gameState.participants.find(p => p.userId === user.id);
if (!myParticipant) return;
// Зрители не могут отвечать на вопросы
if (isSpectator) {
alert('Зрители не могут отвечать на вопросы');
return;
}
// Проверка очереди (только для не-хостов)
if (!isHost && gameState.currentPlayerId !== myParticipant.id) {
alert('Сейчас не ваша очередь!');
// Только хост может кликать на ответы
if (!isHost) {
return;
}
@ -550,7 +543,7 @@ const GamePage = () => {
revealedAnswers={revealedForCurrentQ}
playerScores={playerScores}
currentPlayerId={gameState.currentPlayerId}
onAnswerClick={canPerformActions ? handleAnswerClick : null}
onAnswerClick={isHost ? handleAnswerClick : null}
onPreviousQuestion={isHost && canGoPrev ? handlePrevQuestion : null}
onNextQuestion={isHost && canGoNext ? handleNextQuestion : null}
onSelectPlayer={isHost ? handleSelectPlayer : null}

View file

@ -49,6 +49,9 @@ const RoomPage = () => {
const [joinError, setJoinError] = useState(null);
const [selectedRole, setSelectedRole] = useState('PLAYER');
const [questionPacks, setQuestionPacks] = useState([]);
// Ref для отслеживания попытки присоединения (защита от двойного запроса)
const joinAttemptedRef = useRef(false);
useEffect(() => {
const generateQR = async () => {
@ -131,19 +134,25 @@ const RoomPage = () => {
const isParticipant = participants.some((p) => p.userId === user.id);
if (isParticipant) {
setJoined(true);
joinAttemptedRef.current = true;
return;
}
// Защита от повторной попытки присоединения
if (joinAttemptedRef.current) return;
// Если зрители разрешены, показываем модальное окно выбора роли
if (room.allowSpectators) {
if (!isRoleSelectionModalOpen) {
setIsRoleSelectionModalOpen(true);
joinAttemptedRef.current = true;
}
return;
}
// Если зрители не разрешены, автоматически присоединяемся как PLAYER
// Присоединение разрешено независимо от статуса игры (WAITING, PLAYING, FINISHED)
joinAttemptedRef.current = true;
try {
setJoinError(null);
await joinRoom(room.id, user.id, user.name || 'Гость', 'PLAYER');
@ -154,6 +163,8 @@ const RoomPage = () => {
const errorMessage = error.response?.data?.message || error.message || 'Ошибка при присоединении к комнате';
setJoinError(errorMessage);
alert(errorMessage);
// Сбрасываем флаг при ошибке, чтобы можно было попробовать снова
joinAttemptedRef.current = false;
}
};
@ -177,7 +188,8 @@ const RoomPage = () => {
const errorMessage = error.response?.data?.message || error.message || 'Ошибка при присоединении к комнате';
setJoinError(errorMessage);
alert(errorMessage);
// Открываем модальное окно снова при ошибке
// Сбрасываем флаг и открываем модальное окно снова при ошибке
joinAttemptedRef.current = false;
setIsRoleSelectionModalOpen(true);
}
};