fix(ui): F8-04b lobby — auto-expand first available games sub + hide empty invitations
Tests · UI / test (push) Waiting to run
Tests · UI / test (pull_request) Successful in 2m45s

Two follow-up nits on the F8-04b sidebar:

1. The bare-`lobby` resolver (lobby-screen.svelte) redirected to
   `games-recruitment` unconditionally on mount. With games already
   in the player's roster the sidebar then highlighted the wrong
   sub-page. The resolver now awaits the lobby fan-out + account
   fetch, then hands off to the same `firstVisibleGamesScreen` helper
   the sidebar uses — so a fresh entry with games lands on
   `active-past`, the canonical-order fallback stays `recruitment`.

2. `games-invitations` was unconditionally visible in the sidebar.
   Now it follows the `active-past` rule: hidden until the
   pending-invites list reports >=1. The lobby shell's auto-kick
   effect treats it symmetrically — accepting / declining the last
   invite moves the player to the next visible sub-page once the
   fan-out has resolved.

Acceptance order in games-invitations-screen.acceptInvite was also
swapped to setMyGames-before-removeInvitation: both mutations land
in the same microtask, so the new auto-kick sees the freshly added
game in `myGames` when invitations drop to zero and routes the
player to `active-past` instead of bouncing through `recruitment`.

The visibility predicates and canonical order live in the new
`src/lib/lobby-nav.ts` pure helper, shared between the sidebar and
the resolver so they cannot disagree. Unit tests cover every
combination of (hasMyGames, hasInvitations, isPaidOrDev).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-27 10:17:57 +02:00
parent 8e8b34d112
commit 6fbab5417f
6 changed files with 307 additions and 85 deletions
+12 -4
View File
@@ -61,12 +61,20 @@ contents follow the lobby-data store and the account tier:
| --------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `active-past` | `lobby.my.games.list` | Visible only when the list is non-empty. Empty → the sub-panel is hidden entirely (no empty card surfaces). |
| `recruitment` | `lobby.public.games.list``lobby.my.applications.list` | Always visible. Public games where the caller is **not** the owner; each card surfaces the caller's application status as a chip (`pending` / `approved` / `rejected` / `unknown`) when there is one. Stale `pending`/`approved` applications on closed games render as standalone "applied" cards; stale `rejected`/`unknown` ones are hidden. |
| `invitations` | `lobby.my.invites.list` (status=`pending`) | Always visible. |
| `invitations` | `lobby.my.invites.list` (status=`pending`) | Visible only when the pending-invites list is non-empty. Empty (or while the fan-out is still in flight) → the sub-panel is hidden, mirroring the `active-past` rule. |
| `private games` | `lobby.my.games.list` filtered by `owner_user_id === me``game_type === "private"` | Paid tier only (`account.entitlement.is_paid === true`). `VITE_GALAXY_DEV_AFFORDANCES` overrides for DEV bundles. |
Clicking the `games` parent without choosing a sub-panel resolves to
the first visible sub-panel in the canonical order (e.g. with no
games yet it lands on `recruitment`).
Clicking the `games` parent without choosing a sub-panel — or
arriving on the bare `lobby` alias (a pre-split persisted snapshot,
or a programmatic `appScreen.go("lobby")`) — resolves to the first
visible sub-panel in the canonical order. The resolver awaits the
`lobby.*.list` fan-out and `account` fetch before deciding, so a
fresh entry with games already in the player's roster lands on
`active-past`, an invitee-only account lands on `invitations`, and
the deterministic fallback is `recruitment` (always visible). The
predicates live in `src/lib/lobby-nav.ts` and are shared between
this resolver and the sidebar's submenu, so the two surfaces never
disagree.
### `recruitment` — inline application form