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.
21 const claimed = useRef(false);
22 useEffect(() => {
23 if (claimed.current || session.mySeat !== null) return;
24 if (seats.some((s) => s.id === null)) {
25 claimed.current = true;
26 session.claimSeat(null);
27 }
28 }, [session, seats]);
29
30 const seated = seats.filter((s) => s.id !== null).length;
31
32 return (
33 <div className="lobby">
34 <h1>台灣麻將</h1>
35 <p className="sub">線上對戰 · online game · {session.playerCount} 人在房 in the room</p>
36 <p className="hint">
37 把這頁的連結傳給朋友,他們一開就進同一房。
38 <br />
39 Share this page's invite link — anyone who opens it lands at this table.
40 </p>
41
42 <div className="pick-grid">
43 {SEATS.map((i) => {
44 const slot = seats[i];
45 const mine = slot.id === me;
46 const taken = slot.id !== null && !mine;
47 return (
48 <button
49 key={i}
50 className={`btn big-btn ${mine ? '' : 'ghost'}`}
51 disabled={taken}
52 onClick={() => !mine && session.claimSeat(i)}
53 >
54 {WIND_NAMES[i]} {WIND_EN[i]}
55 <em>
56 {slot.id === null
57 ? '空位,開局時由電腦代打 · open — a bot if nobody sits'
58 : mine
59 ? `${slot.name || '你'} · you`
60 : slot.name}
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}