Let players voluntarily leave a game

Adds a "🚪 Leave Game" option to the corner menu for every player, so someone
who's done can remove themselves instead of waiting for an admin to kick them.

leave_game reuses the kick mechanics (cards to discard, reference cleanup,
phase re-check) via a shared _remove_player helper; it logs a friendlier
"left the crew" event and, like kick, refuses the last Admin so the table
isn't orphaned. The self-service route POST /game/{gid}/player/{pid}/leave
lives next to join and authenticates on the player's own id (no admin key).
The handler confirms, forgets the saved session, and routes home.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 21:58:07 -07:00
parent 428af784e3
commit e7db19f27e
4 changed files with 141 additions and 24 deletions

View File

@@ -1,11 +1,12 @@
<script>
import { onMount, onDestroy } from 'svelte';
import { push } from 'svelte-spa-router';
import { apiRequest } from '../lib/api';
import { extraMenuLinks } from '../lib/menu';
import { getSuggestion } from '../lib/suggestions';
import { displayName } from '../lib/cards';
import { setPageTitle } from '../lib/title';
import { saveSession } from '../lib/sessions';
import { saveSession, removeSession } from '../lib/sessions';
import LobbyPhase from '../components/LobbyPhase.svelte';
import CharacterCreationPhase from '../components/CharacterCreationPhase.svelte';
@@ -106,6 +107,18 @@
}
}
// Voluntarily remove yourself from the game (cards go to the discard)
async function leaveGame() {
if (!confirm("Leave this game? Your cards go to the discard and you'll need a new invite to rejoin. This can't be undone.")) return;
try {
await apiRequest(`/game/${gameId}/player/${playerId}/leave`, 'POST');
removeSession(gameId, playerId);
push('/');
} catch (err) {
error = err.message;
}
}
// Distinguish tabs/history by the Pi-Rat (and crew) this dashboard is for
$: setPageTitle(state ? displayName(state.player) : null, state?.game?.crew_name);
@@ -150,6 +163,13 @@
}
items.push({ label: '🛠️ Admin', href: `#/game/${gameId}/admin`, title: 'Open the Admin Panel' });
}
if (state?.player) {
items.push({
label: '🚪 Leave Game',
action: leaveGame,
title: 'Remove yourself from this game (your cards go to the discard)',
});
}
extraMenuLinks.set(items);
}