Compare commits

...

4 Commits

Author SHA1 Message Date
Michel ten Voorde
8128ba4744 Cleanup
All checks were successful
Gitea/swiss-client/pipeline/head This commit looks good
2025-11-06 16:42:48 +01:00
Michel ten Voorde
19e4372006 Show substitutions in standings 2025-11-06 16:42:22 +01:00
Michel ten Voorde
7fd84005f9 Show 100 players by default 2025-11-06 16:41:03 +01:00
Michel ten Voorde
a56317fecd Update counter 2025-11-06 16:40:20 +01:00
11 changed files with 142 additions and 13 deletions

View File

@@ -0,0 +1,22 @@
<mat-dialog-content>
<h3>Kies een teller:</h3>
<div class="col-md-6">
<mat-form-field appearance="fill">
<mat-label>Teller</mat-label>
<mat-select [(ngModel)]="counter">
<mat-option>Geen</mat-option>
@for (player of data.availableCounters; track player.playerId) {
<mat-option [value]="player">
{{ player.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</mat-dialog-content>
<mat-dialog-actions>
@if (counter) {
<button mat-button [mat-dialog-close]="{counter: counter}">Opslaan</button>
}
<button mat-button (click)="onAnnulerenClick()">Annuleren</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,4 @@
button:disabled {
cursor: not-allowed;
pointer-events: all !important;
}

View File

@@ -0,0 +1,49 @@
import {Component, inject, Inject} from '@angular/core';
import {
MAT_DIALOG_DATA,
MatDialogActions,
MatDialogClose,
MatDialogContent,
MatDialogRef
} from "@angular/material/dialog";
import {Match} from "../../model/match";
import {MatButton} from "@angular/material/button";
import {TournamentPlayer} from "../../model/tournamentPlayer";
import {MatFormField, MatLabel} from "@angular/material/form-field";
import {MatOption, MatSelect} from "@angular/material/select";
import {FormsModule} from "@angular/forms";
@Component({
selector: 'app-counter-selection',
imports: [
MatDialogContent,
MatButton,
MatDialogClose,
MatDialogActions,
MatFormField,
MatLabel,
MatOption,
MatSelect,
FormsModule,
],
templateUrl: './counter-selection.component.html',
standalone: true,
styleUrl: './counter-selection.component.scss'
})
export class CounterSelectionComponent {
counter: TournamentPlayer;
readonly dialogRef = inject(MatDialogRef<CounterSelectionComponent>);
constructor(@Inject(MAT_DIALOG_DATA) public data: {
match: Match,
availableCounters: TournamentPlayer[]
}) {}
onAnnulerenClick() {
this.dialogRef.close();
}
}

View File

@@ -12,15 +12,24 @@ import {MatTooltip} from '@angular/material/tooltip';
styleUrls: ['./player-display.component.scss'], styleUrls: ['./player-display.component.scss'],
template: ` template: `
@let substitute = getSubstituteForEvent(player, event); @let substitute = getSubstituteForEvent(player, event);
<span [class.has-substitute]="substitute" @if (exlicitSubstitute) {
[matTooltip]="substitute ? 'Valt in voor ' + (player | fullName) : ''" @if (substitute) {
matTooltipPosition="below">{{ substitute || (player | fullName) }}</span> {{ substitute }} (valt in voor {{ player | fullName }})
} @else {
{{ player | fullName }}
}
} @else {
<span [class.has-substitute]="substitute"
[matTooltip]="substitute ? 'Valt in voor ' + (player | fullName) : ''"
matTooltipPosition="below">{{ substitute || (player | fullName) }}</span>
}
` `
}) })
export class PlayerDisplayComponent { export class PlayerDisplayComponent {
@Input({ required: true }) player!: Player; @Input({ required: true }) player!: Player;
@Input({ required: true }) event!: Event; @Input({ required: true }) event!: Event;
@Input({ required: true }) tournament!: Tournament; @Input({ required: true }) tournament!: Tournament;
@Input({ required: false }) exlicitSubstitute: boolean = false;
getSubstituteForEvent(player: Player, event: Event): string | undefined { getSubstituteForEvent(player: Player, event: Event): string | undefined {
const tournamentPlayer = this.tournament.tournamentPlayers.find( const tournamentPlayer = this.tournament.tournamentPlayers.find(

View File

@@ -39,7 +39,8 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table> </table>
<mat-paginator [pageSizeOptions]="[10, 20, 50]" <mat-paginator [pageSizeOptions]="[10, 25, 100]"
[pageSize]="100"
showFirstLastButtons showFirstLastButtons
aria-label="Select page of periodic elements"> aria-label="Select page of periodic elements">
</mat-paginator> </mat-paginator>

View File

@@ -5,3 +5,7 @@ a {
td, th { td, th {
background-color: transparent !important; background-color: transparent !important;
} }
.mat-mdc-row:hover {
background-color: rgba(0, 0, 0, 0.075);
}

View File

@@ -108,7 +108,8 @@
[team]="entry.team" [team]="entry.team"
[event]="this.event" [event]="this.event"
[tournament]="this.tournament" [tournament]="this.tournament"
[inline]="true"> [inline]="true"
[explicitSubstitute]="true">
</app-team-display> </app-team-display>
</td> </td>
<td class="align-middle">{{ entry.played }}</td> <td class="align-middle">{{ entry.played }}</td>

View File

@@ -12,7 +12,8 @@ import {Team} from "../../model/team";
<app-player-display <app-player-display
[player]="team.player1" [player]="team.player1"
[event]="event" [event]="event"
[tournament]="tournament"> [tournament]="tournament"
[exlicitSubstitute]="explicitSubstitute">
</app-player-display> </app-player-display>
@if (event.doublesEvent && team.player2) { @if (event.doublesEvent && team.player2) {
@@ -34,4 +35,5 @@ export class TeamDisplayComponent {
@Input({ required: true }) event!: Event; @Input({ required: true }) event!: Event;
@Input({ required: true }) tournament!: Tournament; @Input({ required: true }) tournament!: Tournament;
@Input({ required: false }) inline: boolean = true; @Input({ required: false }) inline: boolean = true;
@Input({ required: false }) explicitSubstitute: boolean = false;
} }

View File

@@ -158,9 +158,13 @@
</div> </div>
<mat-action-row> <mat-action-row>
<button class="align-baseline" mat-button (click)="editResult(activeMatch.match, activeMatch.event, activeMatch.group, activeMatch.round)"> <button class="align-baseline" mat-button (click)="editResult(activeMatch.match, activeMatch.event, activeMatch.group, activeMatch.round)">
<mat-icon>edit</mat-icon> <mat-icon>leaderboard</mat-icon>
Uitslag invoeren Uitslag invoeren
</button> </button>
<button mat-button (click)="changeCounter(activeMatch.match)">
<mat-icon>person</mat-icon>
Teller wijzigen
</button>
<button mat-button (click)="stopMatch(activeMatch.match)"> <button mat-button (click)="stopMatch(activeMatch.match)">
<mat-icon>stop</mat-icon> <mat-icon>stop</mat-icon>
Wedstrijd stoppen Wedstrijd stoppen
@@ -297,7 +301,6 @@
} }
</tbody> </tbody>
</table> </table>
<!-- }-->
} @else if (round.status == 'IN_PROGRESS') { } @else if (round.status == 'IN_PROGRESS') {
<table class="table table-hover m-4 wide w-95"> <table class="table table-hover m-4 wide w-95">
<tbody> <tbody>
@@ -326,12 +329,16 @@
</button> </button>
} @else if (match.status == 'IN_PROGRESS') { } @else if (match.status == 'IN_PROGRESS') {
<button mat-button (click)="editResult(match, event, group, round)"> <button mat-button (click)="editResult(match, event, group, round)">
<mat-icon>edit</mat-icon> <mat-icon>leaderboard</mat-icon>
Uitslag invoeren Uitslag
</button>
<button mat-button (click)="changeCounter(match)">
<mat-icon>person</mat-icon>
Teller
</button> </button>
<button mat-button (click)="stopMatch(match)"> <button mat-button (click)="stopMatch(match)">
<mat-icon>stop</mat-icon> <mat-icon>stop</mat-icon>
Wedstrijd stoppen Stoppen
</button> </button>
} @else if (match.status == 'FINISHED') { } @else if (match.status == 'FINISHED') {
<div class="row result align-items-center"> <div class="row result align-items-center">
@@ -347,7 +354,7 @@
</button> </button>
<mat-menu #finishedMatchMenu="matMenu"> <mat-menu #finishedMatchMenu="matMenu">
<button mat-menu-item (click)="editResult(match, event, group, round)"> <button mat-menu-item (click)="editResult(match, event, group, round)">
<mat-icon>edit</mat-icon> <mat-icon>leaderboard</mat-icon>
Uitslag bewerken Uitslag bewerken
</button> </button>
</mat-menu> </mat-menu>
@@ -429,7 +436,14 @@
@for (entry of getStandingsForRound(round, group).entries; track entry.position) { @for (entry of getStandingsForRound(round, group).entries; track entry.position) {
<tr> <tr>
<td class="align-middle">{{ entry.position }}</td> <td class="align-middle">{{ entry.position }}</td>
<td class="align-middle">{{ entry.team | teamText }}</td> <td class="align-middle">
<app-team-display
[team]="entry.team"
[event]="event"
[tournament]="this.tournament"
[inline]="true">
</app-team-display>
</td>
<td class="align-middle">{{ entry.played }}</td> <td class="align-middle">{{ entry.played }}</td>
<td class="align-middle"> <td class="align-middle">
@if (entry.played > 0 ) { @if (entry.played > 0 ) {

View File

@@ -35,6 +35,7 @@ import {TournamentPlayersComponent} from "../tournament-players/tournament-playe
import {TournamentPlayer} from "../../model/tournamentPlayer"; import {TournamentPlayer} from "../../model/tournamentPlayer";
import {MatTooltip} from "@angular/material/tooltip"; import {MatTooltip} from "@angular/material/tooltip";
import {TeamDisplayComponent} from "../team-display/team-display.component"; import {TeamDisplayComponent} from "../team-display/team-display.component";
import {CounterSelectionComponent} from "../counter-selection/counter-selection.component";
@Component({ @Component({
selector: 'app-tournament-manage', selector: 'app-tournament-manage',
@@ -367,6 +368,7 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
matchResultDialog = inject(MatDialog); matchResultDialog = inject(MatDialog);
courtSelectionDialog = inject(MatDialog); courtSelectionDialog = inject(MatDialog);
counterSelectionDialog = inject(MatDialog);
editResult(match: Match, event: Event, group: Group, round: Round) { editResult(match: Match, event: Event, group: Group, round: Round) {
this.matchResultDialog.open(MatchResultComponent, { this.matchResultDialog.open(MatchResultComponent, {
@@ -427,6 +429,23 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
return count; return count;
} }
changeCounter(match: Match) {
this.counterSelectionDialog.open(CounterSelectionComponent, {
data: {
match: match,
availableCounters: this.getAvailableCounters(match)
},
minWidth: '800px',
minHeight: '250px'
}).afterClosed().subscribe(result => {
if (result != undefined) {
this.tournamentService.updateCounter(this.tournament.id, match.id, result.counter.playerId).subscribe(data => {
this.tournament = data;
});
}
});
}
} }
class ActiveMatch { class ActiveMatch {

View File

@@ -97,6 +97,10 @@ export class TournamentService {
return this.http.post<Tournament>(`${this.tournamentsUrl}/${tournamentId}/players/${playerId}/substitutions`, substitutions) return this.http.post<Tournament>(`${this.tournamentsUrl}/${tournamentId}/players/${playerId}/substitutions`, substitutions)
} }
public updateCounter(tournamentId: number, matchId: number, counter: number): Observable<Tournament> {
return this.http.patch<Tournament>(`${this.tournamentsUrl}/${tournamentId}/matches/${matchId}/update?counter=${counter}`, null);
}
public addTestData(): Observable<void> { public addTestData(): Observable<void> {
return this.http.get<void>(`${environment.backendUrl}/testdata`); return this.http.get<void>(`${environment.backendUrl}/testdata`);
} }