From c6aaef9d949e4a0dbffad04c5e15c1f2c20d78c4 Mon Sep 17 00:00:00 2001 From: DEV-bot Date: Sun, 1 Mar 2026 15:05:09 +0000 Subject: [PATCH] feat(spa): wire lobby join/start round through vertical slice --- .../app/features/host/host-shell.component.ts | 24 ++++++++---- .../features/player/player-shell.component.ts | 38 ++++++++++++------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/frontend/angular/src/app/features/host/host-shell.component.ts b/frontend/angular/src/app/features/host/host-shell.component.ts index 0085e97..661d90c 100644 --- a/frontend/angular/src/app/features/host/host-shell.component.ts +++ b/frontend/angular/src/app/features/host/host-shell.component.ts @@ -2,6 +2,9 @@ import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; +import { createApiClient } from '../../../../../src/api/client'; +import { createVerticalSliceController } from '../../../../../src/spa/vertical-slice'; + interface SessionDetail { session: { code: string; status: string; current_round: number }; round_question: { id: number; prompt: string; answers: Array<{ text: string }> } | null; @@ -51,6 +54,8 @@ export class HostShellComponent { scoreboardPayload = ''; session: SessionDetail | null = null; + private readonly controller = createVerticalSliceController(createApiClient()); + private normalizeCode(value: string): string { return value.trim().toUpperCase(); } @@ -79,8 +84,11 @@ export class HostShellComponent { this.error = ''; this.scoreboardError = ''; try { - const code = this.normalizeCode(this.sessionCode); - this.session = await this.request(`/lobby/sessions/${encodeURIComponent(code)}`, 'GET'); + const state = await this.controller.hydrateLobby(this.sessionCode); + if (!state.session || state.errorMessage) { + throw new Error(state.errorMessage ?? 'Unknown error'); + } + this.session = state.session as SessionDetail; this.sessionCode = this.session.session.code; this.roundQuestionId = this.session.round_question?.id ? String(this.session.round_question.id) : ''; } catch (error) { @@ -92,11 +100,13 @@ export class HostShellComponent { async startRound(): Promise { await this.runAction(async () => { - const code = this.normalizeCode(this.sessionCode); - await this.request(`/lobby/sessions/${encodeURIComponent(code)}/rounds/start`, 'POST', { - category_slug: this.categorySlug.trim(), - }); - await this.refreshSession(); + const state = await this.controller.startRound(this.sessionCode, this.categorySlug.trim()); + if (!state.session || state.errorMessage) { + throw new Error(state.errorMessage ?? 'Unknown error'); + } + this.session = state.session as SessionDetail; + this.sessionCode = this.session.session.code; + this.roundQuestionId = this.session.round_question?.id ? String(this.session.round_question.id) : ''; }); } diff --git a/frontend/angular/src/app/features/player/player-shell.component.ts b/frontend/angular/src/app/features/player/player-shell.component.ts index f8087de..e1d3df1 100644 --- a/frontend/angular/src/app/features/player/player-shell.component.ts +++ b/frontend/angular/src/app/features/player/player-shell.component.ts @@ -2,6 +2,10 @@ import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; +import { createApiClient } from '../../../../../src/api/client'; +import { createSessionContextStore } from '../../../../../src/spa/session-context-store'; +import { createVerticalSliceController } from '../../../../../src/spa/vertical-slice'; + interface SessionDetail { session: { code: string; status: string; current_round: number }; round_question: { id: number; prompt: string; answers: Array<{ text: string }> } | null; @@ -61,6 +65,9 @@ export class PlayerShellComponent { submitError: { kind: 'lie' | 'guess'; message: string } | null = null; session: SessionDetail | null = null; + private readonly sessionContextStore = createSessionContextStore(); + private readonly controller = createVerticalSliceController(createApiClient(), this.sessionContextStore); + private normalizeCode(value: string): string { return value.trim().toUpperCase(); } @@ -88,8 +95,11 @@ export class PlayerShellComponent { this.loading = true; this.error = ''; try { - const code = this.normalizeCode(this.sessionCode); - this.session = await this.request(`/lobby/sessions/${encodeURIComponent(code)}`, 'GET'); + const state = await this.controller.hydrateLobby(this.sessionCode); + if (!state.session || state.errorMessage) { + throw new Error(state.errorMessage ?? 'Unknown error'); + } + this.session = state.session as SessionDetail; this.sessionCode = this.session.session.code; if (this.session.session.status !== 'guess') { this.selectedGuess = ''; @@ -105,17 +115,19 @@ export class PlayerShellComponent { this.loading = true; this.error = ''; try { - const payload = await this.request<{ - player: { id: number; session_token: string }; - session: { code: string }; - }>('/lobby/sessions/join', 'POST', { - code: this.normalizeCode(this.sessionCode), - nickname: this.nickname.trim(), - }); - this.playerId = payload.player.id; - this.sessionToken = payload.player.session_token; - this.sessionCode = payload.session.code; - await this.refreshSession(); + const state = await this.controller.joinLobby(this.sessionCode, this.nickname); + if (!state.session || state.errorMessage) { + throw new Error(state.errorMessage ?? 'Unknown error'); + } + this.session = state.session as SessionDetail; + this.sessionCode = this.session.session.code; + + const sessionContext = this.sessionContextStore.get(); + this.playerId = sessionContext?.playerId ?? 0; + this.sessionToken = sessionContext?.token ?? ''; + if (this.session.session.status !== 'guess') { + this.selectedGuess = ''; + } } catch (error) { this.error = `Join failed: ${(error as Error).message}`; } finally {