feat(multi): add go back button with extra click penalty

This commit is contained in:
jessy-david-dev
2026-04-11 22:30:47 +02:00
parent d268905f2d
commit 54c4400393
3 changed files with 52 additions and 0 deletions
+13
View File
@@ -18,6 +18,8 @@ type GameScreenProps = {
elapsed: string; elapsed: string;
countdown: number | null; countdown: number | null;
onNavigate: (title: string) => void; onNavigate: (title: string) => void;
onGoBack: () => void;
canGoBack: boolean;
onRetry: () => void; onRetry: () => void;
onNextRound: () => void; onNextRound: () => void;
onResetGame: () => void; onResetGame: () => void;
@@ -36,6 +38,8 @@ export function GameScreen({
elapsed, elapsed,
countdown, countdown,
onNavigate, onNavigate,
onGoBack,
canGoBack,
onRetry, onRetry,
onNextRound, onNextRound,
onResetGame, onResetGame,
@@ -262,6 +266,15 @@ export function GameScreen({
<span>{clicks} clics</span> <span>{clicks} clics</span>
<span className="hidden sm:inline">{myPlayer?.score ?? 0} pts</span> <span className="hidden sm:inline">{myPlayer?.score ?? 0} pts</span>
</div> </div>
{!myFinished && canGoBack && (
<button
onClick={onGoBack}
disabled={loading}
className="min-h-8 px-2 rounded-lg text-xs font-semibold bg-[#242424] border border-[#2e2e2e] text-[#f0f0f0] hover:bg-[#1a1a1a] disabled:opacity-50 cursor-pointer shrink-0"
>
+1
</button>
)}
{!myFinished && ( {!myFinished && (
<button <button
onClick={onSurrender} onClick={onSurrender}
+2
View File
@@ -176,6 +176,8 @@ export function ScreenRouter({
elapsed={fmt(multi.elapsed)} elapsed={fmt(multi.elapsed)}
countdown={multi.countdown} countdown={multi.countdown}
onNavigate={multi.navigate} onNavigate={multi.navigate}
onGoBack={multi.goBack}
canGoBack={multi.canGoBack}
onRetry={multi.retryLoad} onRetry={multi.retryLoad}
onNextRound={handlers.handleNextRound} onNextRound={handlers.handleNextRound}
onResetGame={handlers.handleResetGame} onResetGame={handlers.handleResetGame}
+37
View File
@@ -297,6 +297,41 @@ export function useMultiGame() {
return {}; return {};
} }
const goBack = useCallback(async () => {
if (!room || !playerId || loadingRef.current || room.phase !== "playing") return;
if (historyRef.current.length <= 1) return;
clicksRef.current += 1;
setClicksDisplay(clicksRef.current);
if (!timerStartedRef.current) { timer.start(); timerStartedRef.current = true; }
const newHistory = historyRef.current.slice(0, -1);
const target = newHistory[newHistory.length - 1];
fetch(`/api/rooms/${room.code}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "heartbeat", playerId }),
}).catch(() => {});
const canonical = await loadArticle(target);
if (!canonical) return;
historyRef.current = newHistory;
setHistory(newHistory);
window.scrollTo({ top: 0, behavior: "smooth" });
try {
const res = await fetch(`/api/rooms/${room.code}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "navigate", playerId, article: canonical }),
});
if (res.ok) setRoom((await res.json() as { room: Room }).room);
} catch { /* on continue localement */ }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [room, playerId]);
async function setSearchAllowed(value: boolean) { async function setSearchAllowed(value: boolean) {
if (!room || !playerId) return; if (!room || !playerId) return;
const res = await fetch(`/api/rooms/${room.code}`, { const res = await fetch(`/api/rooms/${room.code}`, {
@@ -390,6 +425,8 @@ export function useMultiGame() {
resetGame, resetGame,
leave, leave,
navigate, navigate,
goBack,
canGoBack: historyRef.current.length > 1,
surrender, surrender,
setSearchAllowed, setSearchAllowed,
restore, restore,