fix(ui): keep lobby/game caches fresh across screens (no stale-status flash)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 48s
CI / gate (pull_request) Successful in 1s
CI / deploy (pull_request) Successful in 58s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 48s
CI / gate (pull_request) Successful in 1s
CI / deploy (pull_request) Successful in 58s
The per-screen in-memory caches (lobbycache, gamecache) were refreshed only by the screen that owns them while it was mounted, so a state change that crossed screens left the other screen's cache stale and it visibly redrew on the next navigation: - game -> lobby: the player's own move advanced the game cache but not the lobby snapshot, and an own move carries no self-directed push event, so returning to the lobby painted the pre-move status until the background refresh corrected it. - lobby -> game (and from any other screen): an opponent's move / game-over refreshed the lobby (while mounted) but never the per-game cache, so opening that game flashed the pre-move board. Make cache freshness cross-screen, owned by the single global stream handler that runs for every live event regardless of the mounted screen: - patchLobbyGame upserts the affected game's GameView into the lobby snapshot; the global handler calls it on opponent_moved / game_over / opponent_joined and on a match_found / game_started seed (so a game started elsewhere is present too). The game board still mirrors the player's own move and its own load() — the two updates no live event carries. - advanceCached (a pure wrapper over the existing delta reducers) advances a not-currently-viewed game's cache from opponent_moved / game_over; the game in view is skipped so its mounted board stays the sole owner (no double apply). End-state behaviour is unchanged (the background refresh always reconciled); this removes the transient stale frame. Unit-tested patchLobbyGame and advanceCached; docs/UI_DESIGN.md updated.
This commit is contained in:
@@ -24,6 +24,24 @@ export function setLobby(s: LobbySnapshot): void {
|
||||
snapshot = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* patchLobbyGame upserts the given game into the cached lobby — replacing the matching entry, or
|
||||
* prepending it when absent — so a game-state change seen while the lobby is unmounted (the player's
|
||||
* own move, or any live game event the global stream handler applies from another screen) is already
|
||||
* reflected the next time the lobby renders from the snapshot, instead of showing the stale status
|
||||
* until the background refresh lands. Prepending a freshly started game likewise lets it appear at
|
||||
* once. It is a no-op only when there is no snapshot yet (the lobby cold-loads on its first mount).
|
||||
* The lobby re-groups and re-sorts on render, so the insert position carries no meaning.
|
||||
*/
|
||||
export function patchLobbyGame(g: GameView): void {
|
||||
if (!snapshot) return;
|
||||
const i = snapshot.games.findIndex((x) => x.id === g.id);
|
||||
const games = snapshot.games.slice();
|
||||
if (i === -1) games.unshift(g);
|
||||
else games[i] = g;
|
||||
snapshot = { ...snapshot, games };
|
||||
}
|
||||
|
||||
/** clearLobby drops the cached lobby (called on logout). */
|
||||
export function clearLobby(): void {
|
||||
snapshot = null;
|
||||
|
||||
Reference in New Issue
Block a user