dcrey7's picture
Upload 522 files
811126d verified
"use client";
import { useState, useEffect, useRef } from "react";
import { useParams, useRouter } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { ArrowLeft, Mic, MicOff } from "lucide-react";
import Link from "next/link";
import { useGameSocket } from "@/hooks/use-game-socket";
import "../../styles/background-pattern.css";
interface Player {
id: number;
name: string;
avatar: string;
isReady: boolean;
isSpeaking: boolean;
}
interface GameState {
id: number;
status: "PLAYING" | "FINISHED";
players: Player[];
currentRound: number;
totalRounds: number;
currentSpeaker?: Player;
imposteur?: Player;
}
export default function GamePage() {
const params = useParams();
const router = useRouter();
const [gameState, setGameState] = useState<GameState | null>(null);
const [isMuted, setIsMuted] = useState(true);
const [currentUserId, setCurrentUserId] = useState<number | null>(null);
const audioRef = useRef<HTMLAudioElement>(null);
const { startCall, handleIncomingAudio, socket } = useGameSocket(
params.inviteCode as string
);
useEffect(() => {
// Récupérer l'ID de l'utilisateur depuis les cookies
const userId = document.cookie.match(/userId=(\d+)/)?.[1];
if (!userId) {
router.push("/");
return;
}
setCurrentUserId(parseInt(userId));
// Récupérer l'état initial du jeu
fetchGameState();
}, []);
const fetchGameState = async () => {
try {
const response = await fetch(`/api/group/${params.inviteCode}`);
if (!response.ok)
throw new Error("Erreur lors de la récupération du jeu");
const data = await response.json();
setGameState(data);
} catch (error) {
console.error("Erreur:", error);
alert("Impossible de récupérer l'état du jeu");
}
};
const toggleMicrophone = async () => {
try {
if (isMuted) {
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
});
await startCall(stream);
} else {
// Arrêter le flux audio
const audioTracks = audioRef.current?.srcObject as MediaStream;
audioTracks?.getTracks().forEach((track) => track.stop());
}
setIsMuted(!isMuted);
} catch (error) {
console.error("Erreur lors de l'accès au microphone:", error);
alert("Impossible d'accéder au microphone");
}
};
useEffect(() => {
if (!socket) return;
// Gérer les événements de jeu
socket.on("gameStateUpdate", (newState: GameState) => {
setGameState(newState);
});
// Gérer l'audio entrant
handleIncomingAudio((stream) => {
if (audioRef.current) {
audioRef.current.srcObject = stream;
audioRef.current.play().catch(console.error);
}
});
return () => {
socket.off("gameStateUpdate");
};
}, [socket]);
if (!gameState) {
return (
<div className="min-h-screen bg-gray-100 flex items-center justify-center">
<div className="text-xl">Chargement...</div>
</div>
);
}
const currentPlayer = currentUserId
? gameState.players.find((p) => p.id === currentUserId)
: null;
const isImposteur = currentPlayer?.id === gameState.imposteur?.id;
return (
<div className="min-h-screen relative overflow-hidden">
<div className="background-pattern" />
<div className="background-overlay" />
<div className="background-vignette" />
<audio ref={audioRef} autoPlay />
<div className="relative z-10 p-4">
<div className="max-w-6xl mx-auto bg-gray-100 bg-opacity-90 backdrop-blur-sm rounded-lg shadow-xl p-8">
<div className="flex justify-between items-center mb-8">
<Link href="/">
<Button
variant="outline"
className="border-orange-400 text-orange-600 hover:bg-orange-100"
>
<ArrowLeft className="mr-2 h-4 w-4" />
Quitter la partie
</Button>
</Link>
<div className="text-center">
<h1 className="text-4xl font-grobold font-normal text-orange-600 mb-2">
Round {gameState.currentRound}/{gameState.totalRounds}
</h1>
{isImposteur && (
<div className="text-red-500 font-bold">
Vous êtes l'imposteur !
</div>
)}
</div>
<Button
onClick={toggleMicrophone}
className={`${
isMuted
? "bg-red-500 hover:bg-red-600"
: "bg-green-500 hover:bg-green-600"
} text-white`}
>
{isMuted ? (
<>
<MicOff className="mr-2 h-5 w-5" />
Micro désactivé
</>
) : (
<>
<Mic className="mr-2 h-5 w-5" />
Micro activé
</>
)}
</Button>
</div>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 mb-8">
{gameState.players.map((player) => (
<div
key={player.id}
className={`flex items-center space-x-4 p-4 rounded-lg ${
player.isSpeaking ? "bg-green-200" : "bg-gray-200"
}`}
>
<Avatar className="w-16 h-16 border-4 border-orange-400">
<AvatarImage src={player.avatar} alt={player.name} />
<AvatarFallback>{player.name[0]}</AvatarFallback>
</Avatar>
<div>
<p className="font-grobold font-normal text-orange-800">
{player.name}
{player.id === currentUserId && " (Vous)"}
</p>
<p
className={`text-${
player.isSpeaking ? "green" : "gray"
}-600`}
>
{player.isSpeaking ? "Parle" : "Silencieux"}
</p>
</div>
</div>
))}
</div>
{gameState.currentSpeaker && (
<div className="text-center text-2xl font-grobold font-normal text-orange-600">
Au tour de {gameState.currentSpeaker.name} de parler !
</div>
)}
</div>
</div>
</div>
);
}