Animation de victoire uniquement à la fin de la partie
Build and Publish Docker Image / build-and-push-image (push) Successful in 1m43s

L'overlay de célébration (confettis + avatar du vainqueur) se rejouait à
chaque consultation d'une partie terminée. Il n'est désormais déclenché
que lorsqu'on arrive depuis la fin de partie (état de navigation
justFinished), état consommé ensuite pour qu'un rechargement ne le rejoue
pas. Depuis l'historique ou l'accueil, l'écran de fin s'affiche sans
célébration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Zed
2026-08-01 11:29:05 +02:00
parent 2ad3ce6f13
commit 13cab31382
2 changed files with 20 additions and 3 deletions
+17 -2
View File
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom"; import { useParams, useNavigate, useLocation } from "react-router-dom";
import { Trophy, Home, Share2, RotateCcw, Clock, MapPin } from "lucide-react"; import { Trophy, Home, Share2, RotateCcw, Clock, MapPin } from "lucide-react";
import * as Icons from "lucide-react"; import * as Icons from "lucide-react";
import { useLiveQuery } from "dexie-react-hooks"; import { useLiveQuery } from "dexie-react-hooks";
@@ -20,7 +20,13 @@ export default function GameOver() {
const { sessionId } = useParams<{ sessionId: string }>(); const { sessionId } = useParams<{ sessionId: string }>();
const navigate = useNavigate(); const navigate = useNavigate();
const [session, setSession] = useState<GameSession | null>(null); const [session, setSession] = useState<GameSession | null>(null);
const [showCelebration, setShowCelebration] = useState(true); // Only celebrate when arriving straight from the end of the game, never when
// browsing a finished game from the history.
const routerLocation = useLocation();
const justFinished = Boolean(
(routerLocation.state as { justFinished?: boolean } | null)?.justFinished,
);
const [showCelebration, setShowCelebration] = useState(justFinished);
const startNewGame = useGameStore((state) => state.startNewGame); const startNewGame = useGameStore((state) => state.startNewGame);
const gameConfig = useGameConfig(session?.gameId); const gameConfig = useGameConfig(session?.gameId);
@@ -47,6 +53,15 @@ export default function GameOver() {
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [sessionId]); }, [sessionId]);
// Consume the flag so reloading or coming back to this screen doesn't replay
// the celebration (history.state survives a page reload).
useEffect(() => {
if (justFinished) {
navigate(routerLocation.pathname, { replace: true, state: null });
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!session) if (!session)
return <div className="p-4 text-center mt-10">Chargement...</div>; return <div className="p-4 text-center mt-10">Chargement...</div>;
+3 -1
View File
@@ -211,7 +211,9 @@ export default function PlayGame() {
} }
await finishGame(winnerIds); await finishGame(winnerIds);
navigate(`/gameover/${activeSession.id}`); // `justFinished` déclenche l'animation de victoire (une seule fois) :
// en venant de l'historique, l'écran de fin s'affiche sans célébration.
navigate(`/gameover/${activeSession.id}`, { state: { justFinished: true } });
}; };
const handleCancelGame = async () => { const handleCancelGame = async () => {