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,16 @@ export interface Account {
|
||||
preferredLanguage: string;
|
||||
timeZone: string;
|
||||
declaredCountry: string;
|
||||
entitlement: AccountEntitlement;
|
||||
}
|
||||
|
||||
// AccountEntitlement is the narrow view of the FBS EntitlementSnapshot
|
||||
// the UI currently consumes. `isPaid` gates lobby affordances tied to
|
||||
// the paid tier (F8-04b: private-games subpage + create-game button).
|
||||
// Other snapshot fields (plan code, expiry timestamps) are intentionally
|
||||
// omitted until a feature needs them.
|
||||
export interface AccountEntitlement {
|
||||
isPaid: boolean;
|
||||
}
|
||||
|
||||
export async function getMyAccount(client: GalaxyClient): Promise<Account> {
|
||||
@@ -119,7 +129,12 @@ function decodeAccountResponse(payload: Uint8Array): Account {
|
||||
return decodeAccountView(view);
|
||||
}
|
||||
|
||||
function decodeAccountView(view: AccountView): Account {
|
||||
// Exported for unit tests that build a synthetic AccountView via the
|
||||
// FBS bindings and assert the resulting Account shape. Runtime callers
|
||||
// reach the same decode path through `getMyAccount` / `updateMyProfile`
|
||||
// / `updateMySettings`.
|
||||
export function decodeAccountView(view: AccountView): Account {
|
||||
const entitlement = view.entitlement();
|
||||
return {
|
||||
userId: view.userId() ?? "",
|
||||
email: view.email() ?? "",
|
||||
@@ -128,5 +143,8 @@ function decodeAccountView(view: AccountView): Account {
|
||||
preferredLanguage: view.preferredLanguage() ?? "",
|
||||
timeZone: view.timeZone() ?? "",
|
||||
declaredCountry: view.declaredCountry() ?? "",
|
||||
entitlement: {
|
||||
isPaid: entitlement?.isPaid() ?? false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user