Files
pirats/frontend/src/pages/Join.svelte
Tim McCarthy 345ef4088f Save active sessions in browser local storage
Joining a game now records the session (game ID, player ID, plus
player/rat/crew names) in localStorage via the new lib/sessions.js, and
the dashboard keeps it enriched as state loads (so the rat name tracks
earned Names). The home page lists saved sessions in a "Rejoin a Crew"
menu, most-recent first, alongside creating a new game.

Deleting an entry only touches localStorage, never the backend, and is
undoable: the row greys out with an Undo button and is dropped from
storage immediately, so a page refresh finalizes the removal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 21:14:27 -07:00

76 lines
2.7 KiB
Svelte

<script>
import { onMount } from 'svelte';
import { push } from 'svelte-spa-router';
import { apiRequest } from '../lib/api';
import { setPageTitle } from '../lib/title';
import { saveSession } from '../lib/sessions';
export let params = {};
onMount(() => setPageTitle('Join the Crew'));
let gameId = params.id;
let playerName = '';
let error = '';
let joining = false;
// We can extract ?creator=true from $querystring if needed,
// though the backend determines creator based on if they are the first player.
// For UI purposes, we could show "You are the creator" if we want.
async function joinGame() {
if (!playerName.trim()) return;
joining = true;
error = '';
try {
const data = await apiRequest(`/game/${gameId}/join`, 'POST', { name: playerName });
// Remember this session so the home page can offer a rejoin link;
// the dashboard enriches it with crew/rat names once state loads.
saveSession({ gameId, playerId: data.id, playerName });
push(`/game/${gameId}/player/${data.id}`);
} catch (err) {
error = err.message;
joining = false;
}
}
</script>
<div class="welcome-container">
<header class="welcome-hero">
<p class="hero-overline">Rats with Gats</p>
<h1 class="wordmark">Join the Crew</h1>
</header>
<div class="glass-panel creation-card">
<h2>Enter your name</h2>
<p class="info-text" style="margin-bottom: 1rem;">
This is <strong>your</strong> name as a player, not your Pi-Rat's. Your Pi-Rat will be known
by their smell (e.g. "Recruit Gunpowder") until they earn a proper Name in play.
</p>
<form on:submit|preventDefault={joinGame}>
<div class="form-group">
<label for="playerName">Your Name</label>
<input
type="text"
id="playerName"
bind:value={playerName}
required
class="input-field input-large"
autocomplete="off"
autofocus
/>
</div>
{#if error}
<div class="alert alert-danger">{error}</div>
{/if}
<button type="submit" class="btn btn-primary btn-large btn-full mt-4" disabled={joining}>
{joining ? 'Joining...' : 'Join Game'}
</button>
</form>
</div>
<div class="welcome-links">
<a href="/rules" target="_blank" rel="noopener" class="btn btn-secondary">📖 Read the Rules</a>
</div>
</div>