feat(spa): render final leaderboard summary in host shell
This commit is contained in:
@@ -11,10 +11,16 @@ interface SessionDetail {
|
||||
players: Array<{ id: number; nickname: string; score: number }>;
|
||||
}
|
||||
|
||||
interface LeaderboardEntry {
|
||||
id: number;
|
||||
nickname: string;
|
||||
score: number;
|
||||
}
|
||||
|
||||
interface LeaderboardResponse {
|
||||
session: { code: string; status: string; current_round: number };
|
||||
leaderboard: Array<{ id: number; nickname: string; score: number }>;
|
||||
winner?: { id: number; nickname: string; score: number } | null;
|
||||
leaderboard: LeaderboardEntry[];
|
||||
winner?: LeaderboardEntry | null;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -53,6 +59,13 @@ interface LeaderboardResponse {
|
||||
<li *ngFor="let p of session.players">{{ p.nickname }}: {{ p.score }}</li>
|
||||
</ul>
|
||||
<pre *ngIf="scoreboardPayload">{{ scoreboardPayload }}</pre>
|
||||
<div *ngIf="finalLeaderboard.length">
|
||||
<h3>Final leaderboard</h3>
|
||||
<p *ngIf="finalWinner"><strong>Winner:</strong> {{ finalWinner.nickname }} ({{ finalWinner.score }} pts)</p>
|
||||
<ol>
|
||||
<li *ngFor="let entry of finalLeaderboard">{{ entry.nickname }}: {{ entry.score }}</li>
|
||||
</ol>
|
||||
</div>
|
||||
<pre *ngIf="finalLeaderboardPayload">{{ finalLeaderboardPayload }}</pre>
|
||||
</div>
|
||||
`,
|
||||
@@ -68,6 +81,8 @@ export class HostShellComponent {
|
||||
finishError = '';
|
||||
scoreboardPayload = '';
|
||||
finalLeaderboardPayload = '';
|
||||
finalLeaderboard: LeaderboardEntry[] = [];
|
||||
finalWinner: LeaderboardEntry | null = null;
|
||||
session: SessionDetail | null = null;
|
||||
|
||||
private readonly controller = createVerticalSliceController(createApiClient());
|
||||
@@ -110,7 +125,7 @@ export class HostShellComponent {
|
||||
this.sessionCode = this.session.session.code;
|
||||
this.roundQuestionId = this.session.round_question?.id ? String(this.session.round_question.id) : '';
|
||||
if (this.session.session.status !== 'finished') {
|
||||
this.finalLeaderboardPayload = '';
|
||||
this.resetFinalLeaderboard();
|
||||
}
|
||||
} catch (error) {
|
||||
this.error = `Session refresh failed: ${(error as Error).message}`;
|
||||
@@ -129,7 +144,7 @@ export class HostShellComponent {
|
||||
this.sessionCode = this.session.session.code;
|
||||
this.roundQuestionId = this.session.round_question?.id ? String(this.session.round_question.id) : '';
|
||||
this.scoreboardPayload = '';
|
||||
this.finalLeaderboardPayload = '';
|
||||
this.resetFinalLeaderboard();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -183,7 +198,7 @@ export class HostShellComponent {
|
||||
const code = this.normalizeCode(this.sessionCode);
|
||||
await this.request(`/lobby/sessions/${encodeURIComponent(code)}/rounds/next`, 'POST', {});
|
||||
this.scoreboardPayload = '';
|
||||
this.finalLeaderboardPayload = '';
|
||||
this.resetFinalLeaderboard();
|
||||
await this.refreshSession();
|
||||
} catch (error) {
|
||||
this.nextRoundError = `Next round failed: ${(error as Error).message}`;
|
||||
@@ -200,6 +215,13 @@ export class HostShellComponent {
|
||||
const code = this.normalizeCode(this.sessionCode);
|
||||
const payload = await this.request<LeaderboardResponse>(`/lobby/sessions/${encodeURIComponent(code)}/finish`, 'POST', {});
|
||||
this.finalLeaderboardPayload = JSON.stringify(payload, null, 2);
|
||||
this.finalLeaderboard = [...payload.leaderboard].sort((a, b) => {
|
||||
if (b.score !== a.score) {
|
||||
return b.score - a.score;
|
||||
}
|
||||
return a.nickname.localeCompare(b.nickname);
|
||||
});
|
||||
this.finalWinner = payload.winner ?? this.finalLeaderboard[0] ?? null;
|
||||
await this.refreshSession();
|
||||
} catch (error) {
|
||||
this.finishError = `Finish game failed: ${(error as Error).message}`;
|
||||
@@ -208,6 +230,14 @@ export class HostShellComponent {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private resetFinalLeaderboard(): void {
|
||||
this.finalLeaderboardPayload = '';
|
||||
this.finalLeaderboard = [];
|
||||
this.finalWinner = null;
|
||||
}
|
||||
|
||||
private async runAction(action: () => Promise<void>): Promise<void> {
|
||||
this.loading = true;
|
||||
this.error = '';
|
||||
|
||||
Reference in New Issue
Block a user