first commit
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
@if (loading()) {
|
||||
<div class="team-select-loading">
|
||||
<mat-spinner diameter="32" />
|
||||
</div>
|
||||
} @else if (players().length === 0) {
|
||||
<div class="team-select-empty">
|
||||
<p>Du bist noch keinem Team zugeordnet.</p>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="team-select-page">
|
||||
<h1>Team auswählen</h1>
|
||||
<mat-nav-list>
|
||||
@for (player of players(); track player.id) {
|
||||
<a mat-list-item [routerLink]="['/team', player.team?.id, 'overview']">
|
||||
<span matListItemTitle>{{ player.team?.name }}</span>
|
||||
<span matListItemLine>{{ player.firstName }} {{ player.lastName }}</span>
|
||||
</a>
|
||||
}
|
||||
</mat-nav-list>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.team-select-loading,
|
||||
.team-select-empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 60dvh;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.team-select-page {
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
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 { TeamSelect } from './team-select';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { AuthStore } from '../../core/auth/auth-store';
|
||||
import { Player } from '../../models/player.model';
|
||||
|
||||
describe('TeamSelect', () => {
|
||||
let httpMock: HttpTestingController;
|
||||
let router: Router;
|
||||
let authStore: AuthStore;
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [TeamSelect],
|
||||
providers: [provideHttpClient(), provideHttpClientTesting(), provideRouter([])],
|
||||
}).compileComponents();
|
||||
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
router = TestBed.inject(Router);
|
||||
authStore = TestBed.inject(AuthStore);
|
||||
authStore.setSession('token', { id: 42, email: 'a@b.de', firstName: 'A', lastName: 'B' });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
httpMock.verify();
|
||||
});
|
||||
|
||||
it('renders one entry per team when the user has several', async () => {
|
||||
const players: Player[] = [
|
||||
{
|
||||
id: 1,
|
||||
firstName: 'A',
|
||||
lastName: 'B',
|
||||
balance: 0,
|
||||
active: true,
|
||||
team: { id: 5, name: 'Team A', alias: 'a', balance: 0 },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
firstName: 'A',
|
||||
lastName: 'B',
|
||||
balance: 0,
|
||||
active: true,
|
||||
team: { id: 6, name: 'Team B', alias: 'b', balance: 0 },
|
||||
},
|
||||
];
|
||||
|
||||
const fixture = TestBed.createComponent(TeamSelect);
|
||||
fixture.detectChanges();
|
||||
|
||||
httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush(players);
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
const items = fixture.nativeElement.querySelectorAll('a[mat-list-item]');
|
||||
expect(items.length).toBe(2);
|
||||
});
|
||||
|
||||
it('redirects automatically when the user has exactly one team', async () => {
|
||||
const players: Player[] = [
|
||||
{
|
||||
id: 1,
|
||||
firstName: 'A',
|
||||
lastName: 'B',
|
||||
balance: 0,
|
||||
active: true,
|
||||
team: { id: 5, name: 'Team A', alias: 'a', balance: 0 },
|
||||
},
|
||||
];
|
||||
const navigateSpy = vi.spyOn(router, 'navigate');
|
||||
|
||||
const fixture = TestBed.createComponent(TeamSelect);
|
||||
fixture.detectChanges();
|
||||
|
||||
httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush(players);
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(navigateSpy).toHaveBeenCalledWith(['/team', 5, 'overview'], { replaceUrl: true });
|
||||
});
|
||||
|
||||
it('shows an empty state when the user has no teams', async () => {
|
||||
const fixture = TestBed.createComponent(TeamSelect);
|
||||
fixture.detectChanges();
|
||||
|
||||
httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush([]);
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.textContent).toContain('Du bist noch keinem Team zugeordnet.');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Component, effect, inject } from '@angular/core';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
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';
|
||||
|
||||
@Component({
|
||||
selector: 'app-team-select',
|
||||
imports: [RouterLink, MatListModule, MatProgressSpinnerModule],
|
||||
templateUrl: './team-select.html',
|
||||
styleUrl: './team-select.scss',
|
||||
})
|
||||
export class TeamSelect {
|
||||
private readonly authStore = inject(AuthStore);
|
||||
private readonly myTeamsStore = inject(MyTeamsStore);
|
||||
private readonly router = inject(Router);
|
||||
|
||||
protected readonly players = this.myTeamsStore.players;
|
||||
protected readonly loading = this.myTeamsStore.loading;
|
||||
|
||||
constructor() {
|
||||
const userId = this.authStore.currentUser()?.id;
|
||||
if (userId) {
|
||||
this.myTeamsStore.ensureLoaded(userId);
|
||||
}
|
||||
|
||||
effect(() => {
|
||||
const players = this.myTeamsStore.players();
|
||||
if (!this.myTeamsStore.loading() && players.length === 1 && players[0].team) {
|
||||
void this.router.navigate(['/team', players[0].team.id, 'overview'], {
|
||||
replaceUrl: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user