fixes
This commit is contained in:
parent
625c5837ee
commit
35c5fb8cd8
5 changed files with 55 additions and 18 deletions
|
|
@ -305,7 +305,14 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect, On
|
||||||
const isHost = await this.isHost(payload.roomId, payload.userId);
|
const isHost = await this.isHost(payload.roomId, payload.userId);
|
||||||
const isCurrentPlayer = room.currentPlayerId === payload.participantId;
|
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!' });
|
client.emit('error', { message: 'Not your turn!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ export class RoomsService {
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
@ -133,12 +135,14 @@ export class RoomsService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Получаем обновленную комнату со всеми участниками
|
// Получаем обновленную комнату со всеми активными участниками
|
||||||
const updatedRoom = await this.prisma.room.findUnique({
|
const updatedRoom = await this.prisma.room.findUnique({
|
||||||
where: { id: roomId },
|
where: { id: roomId },
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
@ -221,12 +225,14 @@ export class RoomsService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Получаем обновленную комнату со всеми участниками
|
// Получаем обновленную комнату со всеми активными участниками
|
||||||
const updatedRoom = await this.prisma.room.findUnique({
|
const updatedRoom = await this.prisma.room.findUnique({
|
||||||
where: { id: roomId },
|
where: { id: roomId },
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
@ -291,6 +297,8 @@ export class RoomsService {
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
@ -320,6 +328,8 @@ export class RoomsService {
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
@ -367,6 +377,8 @@ export class RoomsService {
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
@ -404,9 +416,13 @@ export class RoomsService {
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
roomPack: true,
|
||||||
|
theme: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -424,9 +440,13 @@ export class RoomsService {
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
roomPack: true,
|
||||||
|
theme: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -445,6 +465,8 @@ export class RoomsService {
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
@ -537,12 +559,14 @@ export class RoomsService {
|
||||||
data: { role: newRole },
|
data: { role: newRole },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Получаем обновленную комнату со всеми участниками
|
// Получаем обновленную комнату со всеми активными участниками
|
||||||
const room = await this.prisma.room.findUnique({
|
const room = await this.prisma.room.findUnique({
|
||||||
where: { id: roomId },
|
where: { id: roomId },
|
||||||
include: {
|
include: {
|
||||||
host: true,
|
host: true,
|
||||||
participants: {
|
participants: {
|
||||||
|
where: { isActive: true },
|
||||||
|
orderBy: { joinedAt: 'asc' },
|
||||||
include: { user: true },
|
include: { user: true },
|
||||||
},
|
},
|
||||||
questionPack: true,
|
questionPack: true,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.question-box {
|
.question-box {
|
||||||
|
|
@ -130,8 +130,9 @@
|
||||||
grid-auto-rows: minmax(auto, clamp(120px, 18vh, 200px));
|
grid-auto-rows: minmax(auto, clamp(120px, 18vh, 200px));
|
||||||
column-gap: clamp(6px, 1.2vw, 12px);
|
column-gap: clamp(6px, 1.2vw, 12px);
|
||||||
row-gap: clamp(6px, 0.8vh, 12px);
|
row-gap: clamp(6px, 0.8vh, 12px);
|
||||||
flex: 1 1 0;
|
flex: 0 1 auto;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
max-height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
align-content: start;
|
align-content: start;
|
||||||
/* Scrollbar styling */
|
/* Scrollbar styling */
|
||||||
|
|
|
||||||
|
|
@ -175,20 +175,13 @@ const GamePage = () => {
|
||||||
// === Handlers для действий игрока ===
|
// === Handlers для действий игрока ===
|
||||||
|
|
||||||
const handleAnswerClick = (answerId, points) => {
|
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);
|
const myParticipant = gameState.participants.find(p => p.userId === user.id);
|
||||||
if (!myParticipant) return;
|
if (!myParticipant) return;
|
||||||
|
|
||||||
// Зрители не могут отвечать на вопросы
|
// Только хост может кликать на ответы
|
||||||
if (isSpectator) {
|
if (!isHost) {
|
||||||
alert('Зрители не могут отвечать на вопросы');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверка очереди (только для не-хостов)
|
|
||||||
if (!isHost && gameState.currentPlayerId !== myParticipant.id) {
|
|
||||||
alert('Сейчас не ваша очередь!');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,7 +543,7 @@ const GamePage = () => {
|
||||||
revealedAnswers={revealedForCurrentQ}
|
revealedAnswers={revealedForCurrentQ}
|
||||||
playerScores={playerScores}
|
playerScores={playerScores}
|
||||||
currentPlayerId={gameState.currentPlayerId}
|
currentPlayerId={gameState.currentPlayerId}
|
||||||
onAnswerClick={canPerformActions ? handleAnswerClick : null}
|
onAnswerClick={isHost ? handleAnswerClick : null}
|
||||||
onPreviousQuestion={isHost && canGoPrev ? handlePrevQuestion : null}
|
onPreviousQuestion={isHost && canGoPrev ? handlePrevQuestion : null}
|
||||||
onNextQuestion={isHost && canGoNext ? handleNextQuestion : null}
|
onNextQuestion={isHost && canGoNext ? handleNextQuestion : null}
|
||||||
onSelectPlayer={isHost ? handleSelectPlayer : null}
|
onSelectPlayer={isHost ? handleSelectPlayer : null}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,9 @@ const RoomPage = () => {
|
||||||
const [joinError, setJoinError] = useState(null);
|
const [joinError, setJoinError] = useState(null);
|
||||||
const [selectedRole, setSelectedRole] = useState('PLAYER');
|
const [selectedRole, setSelectedRole] = useState('PLAYER');
|
||||||
const [questionPacks, setQuestionPacks] = useState([]);
|
const [questionPacks, setQuestionPacks] = useState([]);
|
||||||
|
|
||||||
|
// Ref для отслеживания попытки присоединения (защита от двойного запроса)
|
||||||
|
const joinAttemptedRef = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const generateQR = async () => {
|
const generateQR = async () => {
|
||||||
|
|
@ -131,19 +134,25 @@ const RoomPage = () => {
|
||||||
const isParticipant = participants.some((p) => p.userId === user.id);
|
const isParticipant = participants.some((p) => p.userId === user.id);
|
||||||
if (isParticipant) {
|
if (isParticipant) {
|
||||||
setJoined(true);
|
setJoined(true);
|
||||||
|
joinAttemptedRef.current = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Защита от повторной попытки присоединения
|
||||||
|
if (joinAttemptedRef.current) return;
|
||||||
|
|
||||||
// Если зрители разрешены, показываем модальное окно выбора роли
|
// Если зрители разрешены, показываем модальное окно выбора роли
|
||||||
if (room.allowSpectators) {
|
if (room.allowSpectators) {
|
||||||
if (!isRoleSelectionModalOpen) {
|
if (!isRoleSelectionModalOpen) {
|
||||||
setIsRoleSelectionModalOpen(true);
|
setIsRoleSelectionModalOpen(true);
|
||||||
|
joinAttemptedRef.current = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если зрители не разрешены, автоматически присоединяемся как PLAYER
|
// Если зрители не разрешены, автоматически присоединяемся как PLAYER
|
||||||
// Присоединение разрешено независимо от статуса игры (WAITING, PLAYING, FINISHED)
|
// Присоединение разрешено независимо от статуса игры (WAITING, PLAYING, FINISHED)
|
||||||
|
joinAttemptedRef.current = true;
|
||||||
try {
|
try {
|
||||||
setJoinError(null);
|
setJoinError(null);
|
||||||
await joinRoom(room.id, user.id, user.name || 'Гость', 'PLAYER');
|
await joinRoom(room.id, user.id, user.name || 'Гость', 'PLAYER');
|
||||||
|
|
@ -154,6 +163,8 @@ const RoomPage = () => {
|
||||||
const errorMessage = error.response?.data?.message || error.message || 'Ошибка при присоединении к комнате';
|
const errorMessage = error.response?.data?.message || error.message || 'Ошибка при присоединении к комнате';
|
||||||
setJoinError(errorMessage);
|
setJoinError(errorMessage);
|
||||||
alert(errorMessage);
|
alert(errorMessage);
|
||||||
|
// Сбрасываем флаг при ошибке, чтобы можно было попробовать снова
|
||||||
|
joinAttemptedRef.current = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -177,7 +188,8 @@ const RoomPage = () => {
|
||||||
const errorMessage = error.response?.data?.message || error.message || 'Ошибка при присоединении к комнате';
|
const errorMessage = error.response?.data?.message || error.message || 'Ошибка при присоединении к комнате';
|
||||||
setJoinError(errorMessage);
|
setJoinError(errorMessage);
|
||||||
alert(errorMessage);
|
alert(errorMessage);
|
||||||
// Открываем модальное окно снова при ошибке
|
// Сбрасываем флаг и открываем модальное окно снова при ошибке
|
||||||
|
joinAttemptedRef.current = false;
|
||||||
setIsRoleSelectionModalOpen(true);
|
setIsRoleSelectionModalOpen(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue