128 lines
3.5 KiB
React
128 lines
3.5 KiB
React
|
|
import React, { useEffect, useState } from 'react';
|
|||
|
|
import { useParams, useNavigate } from 'react-router-dom';
|
|||
|
|
import { useAuth } from '../context/AuthContext';
|
|||
|
|
import { useRoom } from '../hooks/useRoom';
|
|||
|
|
import QRCode from 'qrcode';
|
|||
|
|
|
|||
|
|
const RoomPage = () => {
|
|||
|
|
const { roomCode } = useParams();
|
|||
|
|
const navigate = useNavigate();
|
|||
|
|
const { user } = useAuth();
|
|||
|
|
const { room, participants, loading, error, joinRoom, startGame } = useRoom(roomCode);
|
|||
|
|
const [qrCode, setQrCode] = useState('');
|
|||
|
|
const [joined, setJoined] = useState(false);
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
const generateQR = async () => {
|
|||
|
|
try {
|
|||
|
|
const url = `${window.location.origin}/join-room?code=${roomCode}`;
|
|||
|
|
const qr = await QRCode.toDataURL(url);
|
|||
|
|
setQrCode(qr);
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error('QR generation error:', err);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (roomCode) {
|
|||
|
|
generateQR();
|
|||
|
|
}
|
|||
|
|
}, [roomCode]);
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
const handleJoin = async () => {
|
|||
|
|
if (room && user && !joined) {
|
|||
|
|
const isParticipant = participants.some((p) => p.userId === user.id);
|
|||
|
|
if (!isParticipant) {
|
|||
|
|
try {
|
|||
|
|
await joinRoom(room.id, user.id, user.name || 'Гость', 'PLAYER');
|
|||
|
|
setJoined(true);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Join error:', error);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
setJoined(true);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
handleJoin();
|
|||
|
|
}, [room, user, participants, joined, joinRoom]);
|
|||
|
|
|
|||
|
|
const handleStartGame = () => {
|
|||
|
|
startGame();
|
|||
|
|
navigate(`/game/${roomCode}`);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (loading) {
|
|||
|
|
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="room-page">
|
|||
|
|
<div className="room-container">
|
|||
|
|
<h1>Комната: {room.code}</h1>
|
|||
|
|
|
|||
|
|
<div className="room-info">
|
|||
|
|
<p>Статус: {room.status === 'WAITING' ? 'Ожидание игроков' : room.status}</p>
|
|||
|
|
<p>Игроков: {participants.length}/{room.maxPlayers}</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{qrCode && (
|
|||
|
|
<div className="qr-code">
|
|||
|
|
<h3>QR-код для присоединения:</h3>
|
|||
|
|
<img src={qrCode} alt="QR Code" />
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
<div className="participants-list">
|
|||
|
|
<h3>Участники:</h3>
|
|||
|
|
<ul>
|
|||
|
|
{participants.map((participant) => (
|
|||
|
|
<li key={participant.id}>
|
|||
|
|
{participant.name} {participant.role === 'HOST' && '(Ведущий)'}
|
|||
|
|
{participant.role === 'SPECTATOR' && '(Зритель)'}
|
|||
|
|
</li>
|
|||
|
|
))}
|
|||
|
|
</ul>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="button-group">
|
|||
|
|
{isHost && room.status === 'WAITING' && (
|
|||
|
|
<button
|
|||
|
|
onClick={handleStartGame}
|
|||
|
|
disabled={participants.length < 2}
|
|||
|
|
className="primary"
|
|||
|
|
>
|
|||
|
|
Начать игру
|
|||
|
|
</button>
|
|||
|
|
)}
|
|||
|
|
<button onClick={() => navigate('/')}>Покинуть комнату</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default RoomPage;
|