fix(ui): F8-04b lobby — auto-expand first available games sub + hide empty invitations
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:
+12
-4
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user