Some checks failed
Publish Docker image / Push Docker image to Docker Hub (push) Failing after 3m43s
212 lines
7.9 KiB
JavaScript
212 lines
7.9 KiB
JavaScript
import { useEffect, useState } from 'react';
|
|
import { useGame } from '../context/GameContext';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
import { faTrophy, faHome, faRedo, faChartLine } from '@fortawesome/free-solid-svg-icons';
|
|
import YouTubeEmbed from './YouTubeEmbed';
|
|
import { getDisplayName } from '../utils/playerUtils';
|
|
|
|
const ResultsScreen = () => {
|
|
const { lobby, currentPlayer, leaveLobby } = useGame();
|
|
const [showBattleHistory, setShowBattleHistory] = useState(false);
|
|
const [confetti, setConfetti] = useState(true);
|
|
|
|
// Gewinner-Informationen
|
|
const winner = lobby?.finalWinner;
|
|
const winnerVideoId = getYouTubeId(winner?.youtubeLink);
|
|
|
|
// Konfetti-Effekt für die Siegerfeier
|
|
useEffect(() => {
|
|
if (confetti) {
|
|
// Konfetti-Animation erstellen
|
|
const createConfetti = () => {
|
|
const confettiContainer = document.createElement('div');
|
|
confettiContainer.className = 'confetti';
|
|
|
|
// Zufällige Position, Größe und Farbe
|
|
const left = Math.random() * 100;
|
|
const colors = ['#f94144', '#f3722c', '#f8961e', '#f9c74f', '#90be6d', '#43aa8b', '#577590'];
|
|
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
const size = Math.random() * 0.7 + 0.3; // Zwischen 0.3 und 1rem
|
|
const rotation = Math.random() * 360; // Zufällige Rotation
|
|
const duration = Math.random() * 3 + 2; // Zwischen 2 und 5 Sekunden
|
|
|
|
confettiContainer.style.left = `${left}%`;
|
|
confettiContainer.style.backgroundColor = color;
|
|
confettiContainer.style.width = `${size}rem`;
|
|
confettiContainer.style.height = `${size * 0.6}rem`;
|
|
confettiContainer.style.transform = `rotate(${rotation}deg)`;
|
|
confettiContainer.style.animation = `confetti-fall ${duration}s linear forwards`;
|
|
|
|
document.querySelector('.results-screen').appendChild(confettiContainer);
|
|
|
|
// Nach Animation entfernen
|
|
setTimeout(() => {
|
|
confettiContainer.remove();
|
|
}, duration * 1000);
|
|
};
|
|
|
|
// Mehrere Konfetti-Stücke erstellen
|
|
const confettiInterval = setInterval(() => {
|
|
for (let i = 0; i < 5; i++) {
|
|
createConfetti();
|
|
}
|
|
}, 200);
|
|
|
|
// Konfetti nach einiger Zeit stoppen
|
|
setTimeout(() => {
|
|
clearInterval(confettiInterval);
|
|
setConfetti(false);
|
|
}, 10000);
|
|
|
|
return () => {
|
|
clearInterval(confettiInterval);
|
|
};
|
|
}
|
|
}, [confetti]);
|
|
|
|
// YouTube-Video-ID aus Link extrahieren
|
|
function getYouTubeId(url) {
|
|
if (!url) return null;
|
|
|
|
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
|
|
const match = url.match(regExp);
|
|
|
|
return (match && match[2].length === 11) ? match[2] : null;
|
|
}
|
|
|
|
// Find the submitter from the player list
|
|
const findSubmitter = (submitterId) => {
|
|
if (!lobby || !lobby.players) return null;
|
|
return lobby.players.find(player => player.id === submitterId);
|
|
};
|
|
|
|
if (!winner) {
|
|
return (
|
|
<div className="results-screen">
|
|
<h2>Ergebnisse werden berechnet...</h2>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Find the player who submitted the winning song
|
|
const submitter = findSubmitter(winner.submittedBy);
|
|
|
|
return (
|
|
<div className="results-screen">
|
|
<header>
|
|
<h1><FontAwesomeIcon icon={faTrophy} /> Gewinner!</h1>
|
|
</header>
|
|
|
|
<div className="winner-card">
|
|
<div className="winner-info">
|
|
<h2>{winner.title}</h2>
|
|
<h3>von {winner.artist}</h3>
|
|
<p className="submitter">
|
|
Eingereicht von: {submitter
|
|
? getDisplayName(submitter, lobby, currentPlayer)
|
|
: (lobby?.settings?.hidePlayerNames ? 'Anonymer Spieler' : winner.submittedByName)}
|
|
</p>
|
|
</div>
|
|
|
|
{winnerVideoId ? (
|
|
<div className="winner-video">
|
|
<YouTubeEmbed videoId={winnerVideoId} autoplay={true} />
|
|
</div>
|
|
) : (
|
|
<div className="winner-placeholder">
|
|
<FontAwesomeIcon icon={faTrophy} size="3x" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="results-actions">
|
|
<button
|
|
className="btn secondary"
|
|
onClick={() => setShowBattleHistory(!showBattleHistory)}
|
|
>
|
|
<FontAwesomeIcon icon={faChartLine} />
|
|
{showBattleHistory ? 'Kampfverlauf ausblenden' : 'Kampfverlauf anzeigen'}
|
|
</button>
|
|
|
|
<button className="btn primary" onClick={leaveLobby}>
|
|
<FontAwesomeIcon icon={faHome} /> Zurück zum Start
|
|
</button>
|
|
</div>
|
|
|
|
{showBattleHistory && (
|
|
<div className="battle-history">
|
|
<h3>Kampfverlauf</h3>
|
|
|
|
<div className="battles-list">
|
|
{lobby?.battles?.map((battle, index) => {
|
|
const isWinner = (battle.song1.id === battle.winner);
|
|
const song1VideoId = getYouTubeId(battle.song1?.youtubeLink);
|
|
const song2VideoId = battle.song2 ? getYouTubeId(battle.song2.youtubeLink) : null;
|
|
|
|
// Find the players who submitted the songs
|
|
const song1Submitter = findSubmitter(battle.song1?.submittedBy);
|
|
const song2Submitter = battle.song2 ? findSubmitter(battle.song2?.submittedBy) : null;
|
|
|
|
// Freilos-Runden behandeln
|
|
const isByeRound = battle.bye === true || !battle.song2;
|
|
|
|
return (
|
|
<div key={index} className="battle-item">
|
|
<div className="battle-header">
|
|
<h4>Runde {battle.round + 1}, Kampf {index + 1} {isByeRound ? "(Automatisches Weiterkommen)" : ""}</h4>
|
|
</div>
|
|
|
|
<div className="battle-songs">
|
|
<div className={`battle-song ${isWinner ? 'winner' : ''}`}>
|
|
<div className="song-info">
|
|
<h5>{battle.song1.title}</h5>
|
|
<p>{battle.song1.artist}</p>
|
|
<span className="votes">{battle.song1Votes} Stimmen</span>
|
|
{!lobby?.settings?.hidePlayerNames && (
|
|
<span className="submitter">
|
|
Eingereicht von: {song1Submitter
|
|
? getDisplayName(song1Submitter, lobby, currentPlayer)
|
|
: battle.song1?.submittedByName || 'Unbekannt'}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="versus">{isByeRound ? 'FREILOS' : 'VS'}</div>
|
|
|
|
{battle.song2 ? (
|
|
<div className={`battle-song ${!isWinner ? 'winner' : ''}`}>
|
|
<div className="song-info">
|
|
<h5>{battle.song2.title}</h5>
|
|
<p>{battle.song2.artist}</p>
|
|
<span className="votes">{battle.song2Votes} Stimmen</span>
|
|
{!lobby?.settings?.hidePlayerNames && (
|
|
<span className="submitter">
|
|
Eingereicht von: {song2Submitter
|
|
? getDisplayName(song2Submitter, lobby, currentPlayer)
|
|
: battle.song2?.submittedByName || 'Unbekannt'}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="battle-song bye">
|
|
<div className="song-info">
|
|
<h5>Automatisches Freilos</h5>
|
|
<p>Kein Gegner</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ResultsScreen;
|