104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
import { useState } from 'react'
|
|
import { createGame, joinGame } from '../api'
|
|
import type { BotDifficulty } from '../api'
|
|
import type { Session } from '../types'
|
|
|
|
const BOT_LEVELS: { value: BotDifficulty; label: string; blurb: string }[] = [
|
|
{ value: 'easy', label: '🐣 Easy', blurb: 'Learns you the ropes' },
|
|
{ value: 'medium', label: '🐺 Medium', blurb: 'Puts up a fight' },
|
|
{ value: 'hard', label: '🦁 Hard', blurb: 'Shows no mercy' },
|
|
]
|
|
|
|
// Home is the create/join screen shown when there's no active session.
|
|
export function Home({ onSession }: { onSession: (s: Session) => void }) {
|
|
const [name, setName] = useState('')
|
|
const [code, setCode] = useState('')
|
|
const [busy, setBusy] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
async function run(fn: () => Promise<Session>) {
|
|
setBusy(true)
|
|
setError(null)
|
|
try {
|
|
onSession(await fn())
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : 'something went wrong')
|
|
} finally {
|
|
setBusy(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="home">
|
|
<div className="home-pets" aria-hidden>
|
|
🐷🦔🐶🦩🐉
|
|
</div>
|
|
<h1 className="home-title">
|
|
Super Auto Pets
|
|
<span className="home-subtitle">The Board Game</span>
|
|
</h1>
|
|
|
|
<div className="home-card">
|
|
<label className="field">
|
|
<span>Your name</span>
|
|
<input
|
|
value={name}
|
|
maxLength={20}
|
|
placeholder="Enter your name"
|
|
onChange={(e) => setName(e.target.value)}
|
|
/>
|
|
</label>
|
|
|
|
<button
|
|
className="btn btn-primary btn-big"
|
|
disabled={busy}
|
|
onClick={() => run(() => createGame(name))}
|
|
>
|
|
Host a new game
|
|
</button>
|
|
|
|
<div className="home-divider">
|
|
<span>or challenge the computer</span>
|
|
</div>
|
|
|
|
<div className="home-bots">
|
|
{BOT_LEVELS.map((b) => (
|
|
<button
|
|
key={b.value}
|
|
className="btn btn-secondary"
|
|
disabled={busy}
|
|
title={b.blurb}
|
|
onClick={() => run(() => createGame(name, b.value))}
|
|
>
|
|
{b.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="home-divider">
|
|
<span>or join a friend</span>
|
|
</div>
|
|
|
|
<div className="home-join">
|
|
<input
|
|
className="code-input"
|
|
value={code}
|
|
maxLength={5}
|
|
placeholder="CODE"
|
|
onChange={(e) => setCode(e.target.value.toUpperCase())}
|
|
/>
|
|
<button
|
|
className="btn btn-secondary"
|
|
disabled={busy || code.length < 5}
|
|
onClick={() => run(() => joinGame(code, name))}
|
|
>
|
|
Join
|
|
</button>
|
|
</div>
|
|
|
|
{error && <div className="home-error">{error}</div>}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|