feat(lobby): F8-04b hierarchical sidebar + paid-tier gate for create-game
Reshape the lobby UI from a single Overview into a two-level sidebar (games · profile · DEV synthetic-reports) with four games sub-panels (active-past · recruitment · invitations · private-games). Move the `create new game` button into the private-games panel, merge the applications section into recruitment cards as status chips, and add DEV-only synthetic-report loader as a top-level screen. Add a paid-tier gate at backend `lobby.game.create`: free callers get `403 forbidden` before the lobby service is invoked. The UI hides the private-games sub-panel + create button on free tier (DEV affordances flag overrides). Update every integration test that creates a game to use a new `testenv.PromoteToPaid` helper; add a new `TestLobbyFlow_FreeUserCreateGameForbidden`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,15 @@
|
||||
|
||||
function describeLobbyError(err: unknown): string {
|
||||
if (err instanceof LobbyError) {
|
||||
// Free-tier callers reach this branch when the backend gate
|
||||
// at `lobby.game.create` rejects them. Show the dedicated
|
||||
// inline message instead of the generic "operation
|
||||
// forbidden" — the user got to this screen via the
|
||||
// `private games` panel, so we want to spell out that the
|
||||
// gate is the tier (not a permission misconfig).
|
||||
if (err.code === "forbidden") {
|
||||
return i18n.t("lobby.create.error.forbidden");
|
||||
}
|
||||
const key = `lobby.error.${err.code}` as TranslationKey;
|
||||
const translated = i18n.t(key);
|
||||
if (translated !== key) {
|
||||
@@ -93,7 +102,10 @@
|
||||
turnSchedule: trimmedSchedule,
|
||||
targetEngineVersion: targetEngineVersion.trim() || DEFAULT_TARGET_ENGINE_VERSION,
|
||||
});
|
||||
appScreen.go("lobby");
|
||||
// Land on the private-games panel where the freshly created
|
||||
// game shows up — the lobby-data store will refresh on next
|
||||
// mount.
|
||||
appScreen.go("games-private-games");
|
||||
} catch (err) {
|
||||
formError = describeLobbyError(err);
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user