3 Commits
Author SHA1 Message Date
tiennm99 1f2624c0e3 fix(web): clear stale rooms on refused resume, harden reconnect paths
A refused resume now leaves the room instead of showing a banner over a
dead board, and /play offers a fresh game there. Entering /play forgets
any stored token so it no longer races StartBotGame. An eliminated
player who reconnects stays a spectator. Held lobby actions wait for the
resume's RoomState; leaving while offline is not held. Chat clears its
draft only when the line was sent and cannot send while offline.

Also: away banners no longer announce every second; game over does not
steal focus from the chat field; the clock offset uses the lowest-RTT
pong; the history export numbers a resumed chain from its real length;
chat replay keeps existing ordinals; one .primary button class replaces
five copies; the footer links the data change list; the online heading
joins the type ramp. New component, connection and storage-guard tests.
2026-09-29 20:33:16 +07:00
tiennm99 9be86a3cad refactor(web): share alert banner and turn actions, fix restyle leaks
Add AlertBanner and turnActions to replace duplicated markup and
wrappers, and share component-test setup.

Fixes: oversized dismiss, help, rules and skip-link text after the type
ramp collapse; report button hover styled as submit; chat draft lost
when the panel folds; resign/claim/kick styles leaking app-wide.
2026-09-28 15:19:59 +07:00
tiennm99 cf48d270de test(web): mount WordInput and GameBoard under jsdom
WordInput: the turn seed fires once per turn and is gated on the connection
(regression test for C6), a reconnect blip mid-turn does not reseed over
what the player typed, a rejection's suggestion fills the field on click,
and the player's own in-turn composition is left alone.

GameBoard: the chat pill renders only when onchatopen is passed, which is
the actual contract between the bot and online routes — a bot game simply
never passes it.
2026-09-21 16:28:36 +07:00