From b03198baa638f1e9c0e806737c84d64805e9fdee Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Mon, 3 Aug 2026 16:19:05 +0200 Subject: [PATCH] feat: wire create-team dialog into team-select --- .../app/features/team-select/team-select.html | 7 +++ .../app/features/team-select/team-select.scss | 6 ++ .../features/team-select/team-select.spec.ts | 55 ++++++++++++++++++- .../app/features/team-select/team-select.ts | 23 +++++++- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.html b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.html index dd5dea9..02c1390 100644 --- a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.html +++ b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.html @@ -1,3 +1,10 @@ +
+ +
+ @if (loading()) {
diff --git a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.scss b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.scss index 3969f21..82a6e28 100644 --- a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.scss +++ b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.scss @@ -1,3 +1,9 @@ +.team-select-toolbar { + display: flex; + justify-content: flex-end; + padding: 1rem 1rem 0; +} + .team-select-loading, .team-select-empty { display: flex; diff --git a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.spec.ts b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.spec.ts index 4ef5fd4..409e643 100644 --- a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.spec.ts +++ b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.spec.ts @@ -2,26 +2,42 @@ import { TestBed } from '@angular/core/testing'; import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { provideRouter, Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { MatDialog } from '@angular/material/dialog'; import { TeamSelect } from './team-select'; import { environment } from '../../../environments/environment'; import { AuthStore } from '../../core/auth/auth-store'; import { Player } from '../../models/player.model'; +import { Team } from '../../models/team.model'; +import { MyTeamsStore } from '../../core/team/my-teams-store'; +import { CreateTeamDialog } from './create-team-dialog/create-team-dialog'; describe('TeamSelect', () => { let httpMock: HttpTestingController; let router: Router; let authStore: AuthStore; + let myTeamsStore: MyTeamsStore; + let dialogClosed: Subject; + let dialog: { open: ReturnType }; beforeEach(async () => { localStorage.clear(); + dialogClosed = new Subject(); + dialog = { open: vi.fn(() => ({ afterClosed: () => dialogClosed.asObservable() })) }; await TestBed.configureTestingModule({ imports: [TeamSelect], - providers: [provideHttpClient(), provideHttpClientTesting(), provideRouter([])], + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + provideRouter([]), + { provide: MatDialog, useValue: dialog }, + ], }).compileComponents(); httpMock = TestBed.inject(HttpTestingController); router = TestBed.inject(Router); authStore = TestBed.inject(AuthStore); + myTeamsStore = TestBed.inject(MyTeamsStore); authStore.setSession('token', { id: 42, email: 'a@b.de', firstName: 'A', lastName: 'B' }); }); @@ -92,4 +108,41 @@ describe('TeamSelect', () => { expect(fixture.nativeElement.textContent).toContain('Du bist noch keinem Team zugeordnet.'); }); + + it('opens the create-team dialog and navigates into the newly created team on success', async () => { + const navigateSpy = vi.spyOn(router, 'navigate'); + const refreshSpy = vi.spyOn(myTeamsStore, 'refresh'); + + const fixture = TestBed.createComponent(TeamSelect); + fixture.detectChanges(); + httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush([]); + await fixture.whenStable(); + fixture.detectChanges(); + + fixture.componentInstance['createTeam'](); + expect(dialog.open).toHaveBeenCalledWith(CreateTeamDialog); + + const created: Team = { id: 9, name: '1. Herren', alias: 'a', balance: 0 }; + dialogClosed.next(created); + + expect(refreshSpy).toHaveBeenCalledWith(42); + expect(navigateSpy).toHaveBeenCalledWith(['/team', 9, 'overview']); + + httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush([]); + }); + + it('does not navigate when the create-team dialog is dismissed without a team', async () => { + const navigateSpy = vi.spyOn(router, 'navigate'); + + const fixture = TestBed.createComponent(TeamSelect); + fixture.detectChanges(); + httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush([]); + await fixture.whenStable(); + fixture.detectChanges(); + + fixture.componentInstance['createTeam'](); + dialogClosed.next(undefined); + + expect(navigateSpy).not.toHaveBeenCalled(); + }); }); diff --git a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.ts b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.ts index c389aac..d053b39 100644 --- a/myteamwallet_frontend_modern/src/app/features/team-select/team-select.ts +++ b/myteamwallet_frontend_modern/src/app/features/team-select/team-select.ts @@ -1,13 +1,18 @@ import { Component, effect, inject } from '@angular/core'; import { Router, RouterLink } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; import { MatListModule } from '@angular/material/list'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { AuthStore } from '../../core/auth/auth-store'; import { MyTeamsStore } from '../../core/team/my-teams-store'; +import { Team } from '../../models/team.model'; +import { CreateTeamDialog } from './create-team-dialog/create-team-dialog'; @Component({ selector: 'app-team-select', - imports: [RouterLink, MatListModule, MatProgressSpinnerModule], + imports: [RouterLink, MatButtonModule, MatIconModule, MatListModule, MatProgressSpinnerModule], templateUrl: './team-select.html', styleUrl: './team-select.scss', }) @@ -15,6 +20,7 @@ export class TeamSelect { private readonly authStore = inject(AuthStore); private readonly myTeamsStore = inject(MyTeamsStore); private readonly router = inject(Router); + private readonly dialog = inject(MatDialog); protected readonly players = this.myTeamsStore.players; protected readonly loading = this.myTeamsStore.loading; @@ -34,4 +40,19 @@ export class TeamSelect { } }); } + + protected createTeam(): void { + this.dialog + .open(CreateTeamDialog) + .afterClosed() + .subscribe((team: Team | undefined) => { + if (!team) return; + + const userId = this.authStore.currentUser()?.id; + if (userId) { + this.myTeamsStore.refresh(userId); + } + void this.router.navigate(['/team', team.id, 'overview']); + }); + } }