fix: show finished games on watch page instead of hanging spinner (#16)

Summary
▎
▎ - Opening a finished game caused an infinite spinner because the NDJSON stream never delivers events for finished games — it just hangs waiting for events that will never come
▎ - Fix: fetch the full game state via REST on load (GET .../game/{gameId}), apply it to the board immediately, and only open the stream subscription if the game is still ongoing or pending
▎
▎ Changes
▎
▎ - tournament-watch.component.ts — REST fetch now drives the initial state; stream is only started conditionally; extracted applySnapshot(), isFinished(), subscribeToStream()
▎
▎ Test plan
▎
▎ - [ ] Finished game: board shows final position, correct status label, no spinner
▎ - [ ] Live game: board shows current position, stream updates continue to work
▎ - [ ] Pending game: stream starts and updates once the game begins

---------

Co-authored-by: LQ63 <lkhermann@web.de>
Reviewed-on: #16
This commit was merged in pull request #16.
This commit is contained in:
2026-06-29 09:47:40 +02:00
parent 8603222ab4
commit 828c2a03c1
2 changed files with 52 additions and 7 deletions
@@ -59,19 +59,43 @@ export class TournamentWatchComponent implements OnInit {
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: game => {
this.whiteName = game.white?.name ?? null;
this.blackName = game.black?.name ?? null;
this.applySnapshot(game);
this.connecting = false;
if (!this.isFinished(game.status)) {
this.subscribeToStream();
}
},
error: err => {
this.connecting = false;
this.error = (err as Error).message ?? 'Failed to load game.';
},
});
}
private applySnapshot(game: GameStateSnapshot): void {
this.whiteName = game.white?.name ?? null;
this.blackName = game.black?.name ?? null;
this.snapshot = game;
this.fen = game.fen;
this.turn = game.turn;
this.status = game.status;
this.winner = game.winner;
this.clock = game.clock ?? null;
this.moves = game.moves ? game.moves.split(/\s+/).filter(Boolean) : [];
}
private isFinished(status: GameStatus): boolean {
return status !== 'pending' && status !== 'ongoing';
}
private subscribeToStream(): void {
this.stream.streamGame(this.serverUrl, this.tournamentId, this.gameId)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: ev => this.apply(ev),
error: err => {
this.connecting = false;
this.error = (err as Error).message ?? 'Stream failed.';
}
},
});
}