anvilsign in

collin/mahjong

1import { useEffect, useRef } from 'react';
2import type { Prefs } from '../game/prefs';
3import { WIND_EN, WIND_NAMES } from '../game/tiles';
4import type { SeatId } from '../game/types';
5import type { NetSession } from '../net/session';
6import { Bi } from './Bi';
7
8const SEATS: SeatId[] = [0, 1, 2, 3];
9
10/**
11 * The room before the deal: who is here, who is sitting where, and — for the
12 * host — the button that starts it. Seats nobody takes go to the computer, so
13 * two friends and two bots is a game, not a wait.
14 */
15export function OnlineLobby({ session, prefs }: { session: NetSession; prefs: Prefs }) {
16 const seats = session.seats;
17 const me = session.room.me.id;
18
19 // Walking in unseated: take the first free chair rather than making everyone
20 // pick one. Moving is one tap on another seat — including one somebody
21 // already holds, which is how two people share a hand.
22 const claimed = useRef(false);
23 useEffect(() => {
24 if (claimed.current || session.mySeat !== null) return;
25 if (seats.some((s) => s.ids.length === 0)) {
26 claimed.current = true;
27 session.claimSeat(null);
28 }
29 }, [session, seats]);
30
31 const seated = seats.filter((s) => s.ids.length > 0).length;
32
33 return (
34 <div className="lobby">
35 <h1>台灣麻將</h1>
36 <p className="sub">線上對戰 · online game · {session.playerCount} 人在房 in the room</p>
37 <p className="hint">
38 把這頁的連結傳給朋友,他們一開就進同一房。
39 <br />
40 Share this page's invite link — anyone who opens it lands at this table.
41 </p>
42
43 <div className="pick-grid">
44 {SEATS.map((i) => {
45 const slot = seats[i];
46 const mine = slot.ids.includes(me);
47 const held = slot.ids.length;
48 return (
49 <button
50 key={i}
51 className={`btn big-btn ${mine ? '' : 'ghost'}`}
52 onClick={() => !mine && session.claimSeat(i)}
53 >
54 {WIND_NAMES[i]} {WIND_EN[i]}
55 <em>
56 {held === 0
57 ? '空位,開局時由電腦代打 · open — a bot if nobody sits'
58 : mine
59 ? `${slot.name || '你'} · you${held > 1 ? ` +${held - 1}` : ''}`
60 : `${slot.name}${held > 1 ? ` +${held - 1}` : ''} · 可同坐 join them`}
61 </em>
62 </button>
63 );
64 })}
65 </div>
66
67 <div className="lobby-buttons">
68 {session.isHost ? (
69 <button
70 className="btn big-btn"
71 disabled={seated === 0}
72 onClick={() => session.startOnline(prefs.rules)}
73 >
74 <Bi zh="開局" en="Deal" sub={seated < 4 ? `${4 - seated} 個電腦 bots fill in` : undefined} />
75 </button>
76 ) : (
77 <p className="hint">等房主開局 · waiting for the host to deal</p>
78 )}
79 </div>
80 {session.err && <p className="hint">{session.err}</p>}
81 </div>
82 );
83}