From 5b5fd6f027b4aedb951a802725fcd929d514c359 Mon Sep 17 00:00:00 2001 From: Janis Eccarius Date: Sun, 21 Jun 2026 15:40:12 +0200 Subject: [PATCH] fix(tournaments): load both user bots and official bots in join dialog openJoinDialog now fetches user bots and official bots in parallel via forkJoin. Each section shows its own empty state independently. Official bot difficulty buttons are hidden when no official bots are registered. User bots empty state links to /bots to create one. Disables all join buttons while any join is in progress. Co-Authored-By: Claude Sonnet 4.6 --- .../tournaments/tournaments.component.html | 86 ++++++++++--------- .../tournaments/tournaments.component.ts | 12 ++- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/app/pages/tournaments/tournaments.component.html b/src/app/pages/tournaments/tournaments.component.html index 600839d..bbad48d 100644 --- a/src/app/pages/tournaments/tournaments.component.html +++ b/src/app/pages/tournaments/tournaments.component.html @@ -202,53 +202,57 @@ Join with a bot -

Select an official (engine-backed) bot to enter this tournament. These are the bots that actually play their moves.

- @if (botsLoading) {
Loading bots…
- } @else if (userBots.length === 0) { -

No official bots are available. The official-bots engine service must be running to register them.

} @else { -
- @for (bot of userBots; track bot.id) { - - } -
- } - - @if (joinError) { -
{{ joinError }}
- } - -
- or join with an official bot -
- -
- @for (d of officialDifficulties; track d) { - } - {{ d | titlecase }} - +
} - - @if (officialJoinError) { -
{{ officialJoinError }}
+ @if (joinError) { +
{{ joinError }}
+ } + +
+ or join with an official bot +
+ + @if (officialBots.length === 0) { +

No official bots are available. The official-bots engine service must be running to register them.

+ } @else { +
+ @for (d of officialDifficulties; track d) { + + } +
+ } + + @if (officialJoinError) { +
{{ officialJoinError }}
+ } } diff --git a/src/app/pages/tournaments/tournaments.component.ts b/src/app/pages/tournaments/tournaments.component.ts index c924757..48ab90e 100644 --- a/src/app/pages/tournaments/tournaments.component.ts +++ b/src/app/pages/tournaments/tournaments.component.ts @@ -3,6 +3,7 @@ import { CommonModule, TitleCasePipe } from '@angular/common'; import { Router, RouterLink } from '@angular/router'; import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { forkJoin } from 'rxjs'; import { TournamentService } from '../../services/tournament.service'; import { AuthService } from '../../services/auth.service'; import { BotService } from '../../services/bot.service'; @@ -58,6 +59,7 @@ export class TournamentsComponent implements OnInit { joinDialogTournamentId: string | null = null; userBots: Bot[] = []; + officialBots: Bot[] = []; botsLoading = false; joiningBotId: string | null = null; joinError: string | null = null; @@ -175,16 +177,22 @@ export class TournamentsComponent implements OnInit { this.joinDialogTournamentId = tournamentId; this.joinError = null; this.botsLoading = true; - this.botService.listOfficial() + forkJoin({ user: this.botService.list(), official: this.botService.listOfficial() }) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ - next: bots => { this.userBots = bots; this.botsLoading = false; }, + next: ({ user, official }) => { + this.userBots = user; + this.officialBots = official; + this.botsLoading = false; + }, error: () => { this.botsLoading = false; } }); } closeJoinDialog(): void { this.joinDialogTournamentId = null; + this.userBots = []; + this.officialBots = []; this.joiningBotId = null; this.joinError = null; this.joiningOfficialDifficulty = null;