Files
AliasApp/frontend/src/components/Game.tsx
T
2025-12-04 17:25:19 +03:00

137 lines
6.9 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { useGame } from '../hooks/GameContext';
import { motion } from 'framer-motion';
const Game: React.FC = () => {
const { room, currentPlayer, sendGameAction } = useGame();
const [timeLeft, setTimeLeft] = useState(0);
if (!room || !currentPlayer) return null;
const currentTeam = room.teams[room.currentTeamIndex];
// Determine who is describing:
// The `nextDescriberIndex` points to the NEXT player to describe, or the CURRENT one if the round is active?
// In `finishRound` (backend), we increment it. So during the round, it points to the CURRENT describer.
const describerId = currentTeam.playerIds[currentTeam.nextDescriberIndex];
const isMyTurn = currentPlayer.sessionId === describerId;
const isMyTeam = currentPlayer.teamId === currentTeam.id;
useEffect(() => {
if (room.roundEndTime) {
const interval = setInterval(() => {
const remaining = Math.max(0, Math.ceil((room.roundEndTime! - Date.now()) / 1000));
setTimeLeft(remaining);
// If time is up, we could trigger something, but backend controls the flow usually.
// However, to be responsive, we can show "Time's up" or similar.
}, 500);
return () => clearInterval(interval);
}
}, [room.roundEndTime]);
const handleAction = (action: 'GUESS' | 'SKIP') => {
sendGameAction(action);
// Add haptic feedback here if using Telegram SDK
};
return (
<div className="flex flex-col h-screen bg-gray-900 text-white p-4 overflow-hidden">
{/* Header Info */}
<div className="flex justify-between items-start mb-4">
<div className="flex flex-col">
<span className="text-sm text-gray-400">Ход команды:</span>
<span className="text-xl font-bold text-blue-400">{currentTeam.name}</span>
</div>
<div className="flex flex-col items-end">
<span className="text-sm text-gray-400">Время:</span>
<span className={`text-3xl font-mono font-bold ${timeLeft <= 10 ? 'text-red-500' : 'text-white'}`}>
{timeLeft}
</span>
</div>
</div>
{/* Game Area */}
<div className="flex-1 flex flex-col items-center justify-center relative">
{isMyTurn ? (
// Explainer View
<div className="w-full max-w-xs">
<div className="text-center mb-6">
<p className="text-gray-400 text-sm uppercase tracking-widest">Объясняй</p>
</div>
<motion.div
key={room.currentWord} // Animate when word changes
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className="bg-white text-gray-900 rounded-2xl p-10 shadow-2xl flex items-center justify-center mb-12 aspect-square"
>
<h2 className="text-4xl font-black text-center break-words">{room.currentWord}</h2>
</motion.div>
<div className="grid grid-cols-2 gap-4">
<button
onClick={() => handleAction('SKIP')}
className="bg-gray-700 hover:bg-gray-600 text-white font-bold py-4 rounded-xl transition-colors flex flex-col items-center"
>
<span className="text-2xl mb-1">👎</span>
<span>Пропустить</span>
</button>
<button
onClick={() => handleAction('GUESS')}
className="bg-green-600 hover:bg-green-500 text-white font-bold py-4 rounded-xl transition-colors flex flex-col items-center"
>
<span className="text-2xl mb-1">👍</span>
<span>Угадали</span>
</button>
</div>
<p className="text-center text-xs text-gray-500 mt-6">Свайпы скоро будут доступны</p>
</div>
) : isMyTeam ? (
// Guesser (My Team) View
<div className="text-center">
<div className="mb-8">
<div className="w-20 h-20 bg-blue-500 rounded-full mx-auto flex items-center justify-center text-3xl font-bold mb-4 animate-pulse">
👂
</div>
<h3 className="text-2xl font-bold mb-2">Слушайте внимательно!</h3>
<p className="text-gray-400">
<span className="text-white font-bold">{room.players[describerId]?.name || 'Игрок'}</span> объясняет слово.
</p>
</div>
<div className="p-6 bg-gray-800/50 rounded-xl border border-gray-700">
<p className="text-sm text-gray-400">Текущий счет за раунд</p>
<p className="text-4xl font-bold text-green-400">???</p>
</div>
</div>
) : (
// Spectator (Other Team) View
<div className="text-center opacity-75">
<div className="mb-8">
<div className="w-20 h-20 bg-gray-700 rounded-full mx-auto flex items-center justify-center text-3xl font-bold mb-4">
🤫
</div>
<h3 className="text-xl font-bold mb-2">Тихо!</h3>
<p className="text-gray-400">
Сейчас играет команда противников.
</p>
</div>
</div>
)}
</div>
{/* Footer Score */}
<div className="mt-auto pt-6 border-t border-gray-800 flex justify-around">
{room.teams.map(t => (
<div key={t.id} className={`text-center ${t.id === currentTeam.id ? 'opacity-100' : 'opacity-50'}`}>
<p className="text-xs text-gray-500">{t.name}</p>
<p className="text-xl font-bold">{t.score}</p>
</div>
))}
</div>
</div>
);
};
export default Game;