From 6e8335523188f33d5ab9a60b3a833533ab4e47d5 Mon Sep 17 00:00:00 2001 From: thibaud-leclere Date: Sat, 11 Apr 2026 10:58:33 +0200 Subject: [PATCH] fix: reveal grid solutions when abandoning game --- assets/react/controllers/GameGrid.jsx | 4 +- assets/react/controllers/GameRow.jsx | 4 +- assets/react/controllers/LetterInput.jsx | 13 +++-- assets/styles/app.css | 22 ++++++++ src/Controller/GameController.php | 4 +- src/Controller/HomepageController.php | 21 ++++++++ templates/homepage/index.html.twig | 64 +++++++++++++----------- 7 files changed, 97 insertions(+), 35 deletions(-) diff --git a/assets/react/controllers/GameGrid.jsx b/assets/react/controllers/GameGrid.jsx index 296dee9..e5976fa 100644 --- a/assets/react/controllers/GameGrid.jsx +++ b/assets/react/controllers/GameGrid.jsx @@ -1,8 +1,7 @@ import React from 'react'; import GameRow from './GameRow'; -import ActorPopover from './ActorPopover'; -export default function GameGrid({ grid, width, middle }) { +export default function GameGrid({ grid, width, middle, revealed = false }) { return (
@@ -34,6 +33,7 @@ export default function GameGrid({ grid, width, middle }) { totalWidth={width} hintType={row.hintType} hintText={row.hintText} + revealed={revealed} /> ); })} diff --git a/assets/react/controllers/GameRow.jsx b/assets/react/controllers/GameRow.jsx index 29e86ad..256bf41 100644 --- a/assets/react/controllers/GameRow.jsx +++ b/assets/react/controllers/GameRow.jsx @@ -6,7 +6,7 @@ function isLetter(ch) { return /[a-zA-Z]/.test(ch); } -export default function GameRow({ actorName, pos, colStart, totalWidth, hintType, hintText }) { +export default function GameRow({ actorName, pos, colStart, totalWidth, hintType, hintText, revealed = false }) { const inputRefs = useRef([]); const letters = actorName.split(''); @@ -57,6 +57,8 @@ export default function GameRow({ actorName, pos, colStart, totalWidth, hintType inputRef={setInputRef(charIndex)} onNext={() => focusNextInput(charIndex, 1)} onPrev={() => focusNextInput(charIndex, -1)} + value={revealed ? ch.toUpperCase() : undefined} + disabled={revealed} /> ); })} diff --git a/assets/react/controllers/LetterInput.jsx b/assets/react/controllers/LetterInput.jsx index fe00e74..e99463f 100644 --- a/assets/react/controllers/LetterInput.jsx +++ b/assets/react/controllers/LetterInput.jsx @@ -1,7 +1,11 @@ -import React, { useRef, useCallback } from 'react'; +import React, { useCallback } from 'react'; -export default function LetterInput({ highlighted, onNext, onPrev, inputRef }) { +export default function LetterInput({ highlighted, onNext, onPrev, inputRef, value, disabled = false }) { const handleKeyUp = useCallback((e) => { + if (disabled || value !== undefined) { + return; + } + if (e.key === 'Backspace') { e.target.value = ''; onPrev?.(); @@ -9,7 +13,7 @@ export default function LetterInput({ highlighted, onNext, onPrev, inputRef }) { e.target.value = e.key.toUpperCase(); onNext?.(); } - }, [onNext, onPrev]); + }, [disabled, onNext, onPrev, value]); return (
@@ -18,6 +22,9 @@ export default function LetterInput({ highlighted, onNext, onPrev, inputRef }) { type="text" maxLength={1} className={`letter-input${highlighted ? ' letter-highlighted' : ''}`} + value={value} + disabled={disabled} + readOnly={value !== undefined} onKeyUp={handleKeyUp} autoComplete="off" /> diff --git a/assets/styles/app.css b/assets/styles/app.css index 34e53b7..2f5382c 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -79,6 +79,12 @@ body { box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.15); } +.letter-input:disabled { + opacity: 1; + cursor: default; + -webkit-text-fill-color: currentColor; +} + .letter-highlighted { background-color: var(--orange-light); border-color: var(--orange); @@ -612,6 +618,22 @@ body { justify-content: flex-start; } +.game-result-banner { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 16px; + padding: 12px 16px; + border: 1px solid var(--border-warm); + border-radius: var(--radius-md); + background: var(--surface-warm); + color: var(--text); + font-size: 14px; + font-weight: 600; +} + .btn-abandon { padding: 7px 16px; background: none; diff --git a/src/Controller/GameController.php b/src/Controller/GameController.php index 8bf76f5..c818c57 100644 --- a/src/Controller/GameController.php +++ b/src/Controller/GameController.php @@ -23,6 +23,7 @@ class GameController extends AbstractController GameRepository $gameRepository, ): Response { $this->validateCsrfToken('game_start', $request); + $request->getSession()->remove('revealed_game_id'); /** @var User|null $user */ $user = $this->getUser(); @@ -109,12 +110,13 @@ class GameController extends AbstractController $game->abandon(); $em->flush(); + $request->getSession()->set('revealed_game_id', $game->getId()); if (!$user) { $request->getSession()->remove('current_game_id'); } - return $this->redirectToRoute('app_homepage'); + return $this->redirectToRoute('app_homepage', ['revealed' => 1]); } private function validateCsrfToken(string $tokenId, Request $request): void diff --git a/src/Controller/HomepageController.php b/src/Controller/HomepageController.php index acf63c4..699b74e 100644 --- a/src/Controller/HomepageController.php +++ b/src/Controller/HomepageController.php @@ -41,6 +41,27 @@ class HomepageController extends AbstractController } } + if ($game === null && $request->query->getBoolean('revealed')) { + $revealedGameId = $request->getSession()->get('revealed_game_id'); + if (is_int($revealedGameId) || ctype_digit((string) $revealedGameId)) { + $revealedGame = $gameRepository->find((int) $revealedGameId); + if ( + $revealedGame instanceof Game + && $revealedGame->getStatus() === Game::STATUS_ABANDONED + && ( + ($user === null && $revealedGame->getUser() === null) + || ($user !== null && $revealedGame->getUser() === $user) + ) + ) { + $game = $revealedGame; + } else { + $request->getSession()->remove('revealed_game_id'); + } + } else { + $request->getSession()->remove('revealed_game_id'); + } + } + if (!$game) { return $this->render('homepage/index.html.twig', [ 'game' => null, diff --git a/templates/homepage/index.html.twig b/templates/homepage/index.html.twig index e992d58..846703b 100644 --- a/templates/homepage/index.html.twig +++ b/templates/homepage/index.html.twig @@ -4,43 +4,51 @@ {% if game %}
-
- -
-

Êtes-vous sûr de vouloir abandonner ?

-
-
- - -
- + {% if game.status == constant('App\\Entity\\Game::STATUS_IN_PROGRESS') %} +
+ +
+

Êtes-vous sûr de vouloir abandonner ?

+
+
+ + +
+ +
-
- + }); + document.addEventListener('click', function(e) { + if (!popover.contains(e.target) && e.target !== trigger) { + popover.classList.remove('open'); + } + }); + })(); + + {% else %} +
+ Partie abandonnée, voici la solution. + Nouvelle partie +
+ {% endif %}