Compare commits
15 Commits
0e1e1932a1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 87d9291bfb | |||
| c646ae15ee | |||
|
|
8128ba4744 | ||
|
|
19e4372006 | ||
|
|
7fd84005f9 | ||
|
|
a56317fecd | ||
|
|
ecbb16776c | ||
|
|
3008f45dfa | ||
|
|
5baf1228f7 | ||
|
|
aacf06e203 | ||
| 368aa53b9d | |||
| 335577fa4d | |||
| 1f55acecd0 | |||
| c1fedd728b | |||
| 0e9e8d1e0f |
@@ -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>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
button:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: all !important;
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,86 +7,76 @@
|
|||||||
<b>{{ data.group.name }} {{ data.round.name }}</b>
|
<b>{{ data.group.name }} {{ data.round.name }}</b>
|
||||||
</div>
|
</div>
|
||||||
</mat-grid-tile>
|
</mat-grid-tile>
|
||||||
<mat-grid-tile>
|
|
||||||
<button type="button" class="btn btn-primary btn-lg" (click)="set21(1, 1)">21</button>
|
|
||||||
</mat-grid-tile>
|
|
||||||
<mat-grid-tile>
|
|
||||||
<button type="button" class="btn btn-primary btn-lg" (click)="set21(1, 2)">21</button>
|
|
||||||
</mat-grid-tile>
|
|
||||||
<mat-grid-tile>
|
|
||||||
<button type="button" class="btn btn-primary btn-lg" (click)="set21(1, 3)">21</button>
|
|
||||||
</mat-grid-tile>
|
|
||||||
|
|
||||||
|
@for (gameNum of [1, 2, 3]; track gameNum) {
|
||||||
|
<mat-grid-tile>
|
||||||
|
<button type="button" class="btn btn-primary btn-lg" (click)="set21(1, gameNum)">21</button>
|
||||||
|
</mat-grid-tile>
|
||||||
|
}
|
||||||
<mat-grid-tile colspan="2">
|
<mat-grid-tile colspan="2">
|
||||||
<div class="w-100" [ngClass]="{'winner': validateResult() == 1}">
|
<div class="w-100" [ngClass]="{'winner': isValidResult == 1}">
|
||||||
<app-team-display
|
<app-team-display
|
||||||
[team]="data.match.team1"
|
[team]="data.match.team1"
|
||||||
[event]="data.event"
|
[event]="data.event"
|
||||||
[tournament]="data.tournament"
|
[tournament]="data.tournament"
|
||||||
[inline]="true">
|
[inline]="false">
|
||||||
</app-team-display>
|
</app-team-display>
|
||||||
</div>
|
</div>
|
||||||
</mat-grid-tile>
|
</mat-grid-tile>
|
||||||
|
|
||||||
|
@for (game of result.games; track $index; let i = $index) {
|
||||||
<mat-grid-tile>
|
<mat-grid-tile>
|
||||||
<mat-form-field appearance="outline" (change)="validateResult()">
|
<mat-form-field appearance="outline">
|
||||||
<input matInput type="number" min="0" max="30" [(ngModel)]="result.games[0].score1">
|
<input matInput
|
||||||
</mat-form-field>
|
type="number"
|
||||||
</mat-grid-tile>
|
min="0"
|
||||||
<mat-grid-tile>
|
max="30"
|
||||||
<mat-form-field appearance="outline" (change)="validateResult()">
|
[(ngModel)]="game.score1"
|
||||||
<input matInput type="number" min="0" max="30" [(ngModel)]="result.games[1].score1">
|
(blur)="complementScores()"
|
||||||
</mat-form-field>
|
(ngModelChange)="validateResult()"
|
||||||
</mat-grid-tile>
|
[tabindex]="i * 2 + 1">
|
||||||
<mat-grid-tile>
|
|
||||||
<mat-form-field appearance="outline" (change)="validateResult()">
|
|
||||||
<input matInput type="number" min="0" max="30" [(ngModel)]="result.games[2].score1">
|
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-grid-tile>
|
</mat-grid-tile>
|
||||||
|
}
|
||||||
|
|
||||||
<mat-grid-tile colspan="2">
|
<mat-grid-tile colspan="2">
|
||||||
<div class="w-100" [ngClass]="{'winner': validateResult() == -1}">
|
<div class="w-100" [ngClass]="{'winner': isValidResult == -1}">
|
||||||
<app-team-display
|
<app-team-display
|
||||||
[team]="data.match.team2"
|
[team]="data.match.team2"
|
||||||
[event]="data.event"
|
[event]="data.event"
|
||||||
[tournament]="data.tournament"
|
[tournament]="data.tournament"
|
||||||
[inline]="true">
|
[inline]="false">
|
||||||
</app-team-display>
|
</app-team-display>
|
||||||
</div>
|
</div>
|
||||||
</mat-grid-tile>
|
</mat-grid-tile>
|
||||||
<mat-grid-tile>
|
|
||||||
<mat-form-field appearance="outline" (change)="validateResult()">
|
|
||||||
<input matInput type="number" min="0" max="30" [(ngModel)]="result.games[0].score2">
|
|
||||||
</mat-form-field>
|
|
||||||
</mat-grid-tile>
|
|
||||||
<mat-grid-tile>
|
|
||||||
<mat-form-field appearance="outline" (change)="validateResult()">
|
|
||||||
<input matInput type="number" min="0" max="30" [(ngModel)]="result.games[1].score2">
|
|
||||||
</mat-form-field>
|
|
||||||
</mat-grid-tile>
|
|
||||||
<mat-grid-tile>
|
|
||||||
<mat-form-field appearance="outline" (change)="validateResult()">
|
|
||||||
<input matInput type="number" min="0" max="30" [(ngModel)]="result.games[2].score2">
|
|
||||||
</mat-form-field>
|
|
||||||
</mat-grid-tile>
|
|
||||||
|
|
||||||
|
@for (game of result.games; track $index; let i = $index) {
|
||||||
<mat-grid-tile>
|
<mat-grid-tile>
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<input matInput
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
max="30"
|
||||||
|
[(ngModel)]="game.score2"
|
||||||
|
(blur)="complementScores()"
|
||||||
|
(ngModelChange)="validateResult()"
|
||||||
|
[tabindex]="i * 2 + 2">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-grid-tile>
|
||||||
|
}
|
||||||
|
<mat-grid-tile></mat-grid-tile>
|
||||||
|
<mat-grid-tile></mat-grid-tile>
|
||||||
|
|
||||||
</mat-grid-tile>
|
@for (gameNum of [1, 2, 3]; track gameNum) {
|
||||||
<mat-grid-tile>
|
<mat-grid-tile>
|
||||||
|
<button type="button" class="btn btn-primary btn-lg" (click)="set21(2, gameNum)">21</button>
|
||||||
</mat-grid-tile>
|
</mat-grid-tile>
|
||||||
<mat-grid-tile>
|
}
|
||||||
<button type="button" class="btn btn-primary btn-lg" (click)="set21(2, 1)">21</button>
|
|
||||||
</mat-grid-tile>
|
|
||||||
<mat-grid-tile>
|
|
||||||
<button type="button" class="btn btn-primary btn-lg" (click)="set21(2, 2)">21</button>
|
|
||||||
</mat-grid-tile>
|
|
||||||
<mat-grid-tile>
|
|
||||||
<button type="button" class="btn btn-primary btn-lg" (click)="set21(2, 3)">21</button>
|
|
||||||
</mat-grid-tile>
|
|
||||||
</mat-grid-list>
|
</mat-grid-list>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button (click)="onAnnulerenClick()">Annuleren</button>
|
<button mat-button (click)="onAnnulerenClick()">Annuleren</button>
|
||||||
<button mat-button [disabled]="validateResult() == 0" [mat-dialog-close]="result">Opslaan</button>
|
<button mat-button [disabled]="isValidResult == 0" [mat-dialog-close]="result">Opslaan</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import {Tournament} from "../../model/tournament";
|
|||||||
export class MatchResultComponent {
|
export class MatchResultComponent {
|
||||||
|
|
||||||
result: Result = new Result();
|
result: Result = new Result();
|
||||||
|
isValidResult: number = 0;
|
||||||
|
|
||||||
constructor(@Inject(MAT_DIALOG_DATA) public data: {match: Match, tournament: Tournament, event: Event, group: Group, round: Round}) {
|
constructor(@Inject(MAT_DIALOG_DATA) public data: {match: Match, tournament: Tournament, event: Event, group: Group, round: Round}) {
|
||||||
this.result.matchId = this.data.match.id;
|
this.result.matchId = this.data.match.id;
|
||||||
@@ -67,6 +68,8 @@ export class MatchResultComponent {
|
|||||||
this.result.games.push(new Game());
|
this.result.games.push(new Game());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.validateResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly dialogRef = inject(MatDialogRef<MatchResultComponent>);
|
readonly dialogRef = inject(MatDialogRef<MatchResultComponent>);
|
||||||
@@ -79,13 +82,18 @@ export class MatchResultComponent {
|
|||||||
this.result.games[game - 1].score2 = 21;
|
this.result.games[game - 1].score2 = 21;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.validateResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
onAnnulerenClick() {
|
onAnnulerenClick() {
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
validateResult(): number {
|
complementScores() {
|
||||||
|
// console.log("in complementScores");
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResult(): void {
|
||||||
let valid : boolean = true;
|
let valid : boolean = true;
|
||||||
valid &&= this.gameValid(this.result.games[0].score1, this.result.games[0].score2);
|
valid &&= this.gameValid(this.result.games[0].score1, this.result.games[0].score2);
|
||||||
valid &&= this.gameValid(this.result.games[1].score1, this.result.games[1].score2);
|
valid &&= this.gameValid(this.result.games[1].score1, this.result.games[1].score2);
|
||||||
@@ -94,7 +102,7 @@ export class MatchResultComponent {
|
|||||||
valid &&= this.gameValid(this.result.games[2].score1, this.result.games[2].score2);
|
valid &&= this.gameValid(this.result.games[2].score1, this.result.games[2].score2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return valid ? this.matchResult(this.result) : 0;
|
this.isValidResult = valid ? this.matchResult(this.result) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gameValid(score1: number, score2: number): boolean {
|
gameValid(score1: number, score2: number): boolean {
|
||||||
@@ -117,29 +125,31 @@ export class MatchResultComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
matchResult(result: Result): number {
|
matchResult(result: Result): number {
|
||||||
let gameBalance = 0;
|
let team1Wins = 0;
|
||||||
if (result.games[0].score1 < result.games[0].score2) {
|
let team2Wins = 0;
|
||||||
gameBalance--;
|
|
||||||
} else {
|
// Count wins for games 1 and 2
|
||||||
gameBalance++;
|
if (result.games[0].score1 > result.games[0].score2) team1Wins++;
|
||||||
|
else team2Wins++;
|
||||||
|
|
||||||
|
if (result.games[1].score1 > result.games[1].score2) team1Wins++;
|
||||||
|
else team2Wins++;
|
||||||
|
|
||||||
|
// If match is already decided (2-0), game 3 shouldn't have scores
|
||||||
|
if (Math.max(team1Wins, team2Wins) == 2) {
|
||||||
|
if (result.games[2].score1 != undefined || result.games[2].score2 != undefined) {
|
||||||
|
return 0; // Invalid
|
||||||
}
|
}
|
||||||
if (result.games[1].score1 < result.games[1].score2) {
|
return team1Wins > team2Wins ? 1 : -1;
|
||||||
gameBalance--;
|
|
||||||
} else {
|
|
||||||
gameBalance++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.abs(gameBalance) == 2 && (result.games[2].score1 != undefined || result.games[2].score2 != undefined)) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Match is 1-1, check game 3
|
||||||
if (result.games[2].score1 != undefined && result.games[2].score2 != undefined) {
|
if (result.games[2].score1 != undefined && result.games[2].score2 != undefined) {
|
||||||
if (result.games[2].score1 < result.games[2].score2) {
|
if (result.games[2].score1 > result.games[2].score2) team1Wins++;
|
||||||
gameBalance--;
|
else team2Wins++;
|
||||||
} else {
|
return team1Wins > team2Wins ? 1 : -1;
|
||||||
gameBalance++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Math.sign(gameBalance);
|
return 0; // Incomplete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,17 @@
|
|||||||
<div class="nobreak">
|
<div class="nobreak">
|
||||||
<mat-card appearance="outlined">
|
<mat-card appearance="outlined">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<h6>{{ tournament.name }}</h6>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<h5>{{ tournament.name }}</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 text-end">
|
||||||
|
{{ group.name }} {{ round.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<div class="row align-middle">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<b>
|
<b>
|
||||||
<app-team-display
|
<app-team-display
|
||||||
@@ -35,12 +42,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
|
<b>
|
||||||
<app-team-display
|
<app-team-display
|
||||||
[team]="match.team2"
|
[team]="match.team2"
|
||||||
[event]="this.event"
|
[event]="this.event"
|
||||||
[tournament]="this.tournament"
|
[tournament]="this.tournament"
|
||||||
[inline]="true">
|
[inline]="true">
|
||||||
</app-team-display>
|
</app-team-display>
|
||||||
|
</b>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<mat-form-field appearance="outline">
|
<mat-form-field appearance="outline">
|
||||||
@@ -62,9 +71,6 @@
|
|||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<u>Graag de winnaar omcirkelen</u>
|
<u>Graag de winnaar omcirkelen</u>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 text-end">
|
|
||||||
{{ group.name }} {{ round.name }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
@if (exlicitSubstitute) {
|
||||||
|
@if (substitute) {
|
||||||
|
{{ substitute }} (valt in voor {{ player | fullName }})
|
||||||
|
} @else {
|
||||||
|
{{ player | fullName }}
|
||||||
|
}
|
||||||
|
} @else {
|
||||||
<span [class.has-substitute]="substitute"
|
<span [class.has-substitute]="substitute"
|
||||||
[matTooltip]="substitute ? 'Valt in voor ' + (player | fullName) : ''"
|
[matTooltip]="substitute ? 'Valt in voor ' + (player | fullName) : ''"
|
||||||
matTooltipPosition="below">{{ substitute || (player | fullName) }}</span>
|
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(
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,14 +18,23 @@
|
|||||||
@if (eventRegistration.doublesEvent) {
|
@if (eventRegistration.doublesEvent) {
|
||||||
<mat-form-field appearance="fill">
|
<mat-form-field appearance="fill">
|
||||||
<mat-label>Partner</mat-label>
|
<mat-label>Partner</mat-label>
|
||||||
<mat-select [value]="eventRegistration.partner" [disabled]="!tournamentRegistration.editable || !eventRegistration.registered" [(ngModel)]="eventRegistration.partner">
|
<input type="text"
|
||||||
<mat-option>Geen</mat-option>
|
matInput
|
||||||
@for (player of getRelevantPlayers(eventRegistration.type); track player.id) {
|
[matAutocomplete]="auto"
|
||||||
|
[disabled]="!tournamentRegistration.editable || !eventRegistration.registered"
|
||||||
|
[(ngModel)]="eventRegistration.partner"
|
||||||
|
(input)="onPartnerSearch($any($event.target).value, eventRegistration)"
|
||||||
|
[name]="'partner-' + eventRegistration.id">
|
||||||
|
<mat-autocomplete #auto="matAutocomplete"
|
||||||
|
[displayWith]="displayPartnerName.bind(this)"
|
||||||
|
(optionSelected)="onPartnerSelected($event, eventRegistration)">
|
||||||
|
<mat-option [value]="null">Geen</mat-option>
|
||||||
|
@for (player of getFilteredPlayers(eventRegistration); track player.id) {
|
||||||
<mat-option [value]="player.id">
|
<mat-option [value]="player.id">
|
||||||
{{ player | fullName }}
|
{{ player | fullName }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-autocomplete>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import {RegistrationService} from "../../service/registration.service";
|
|||||||
import {MatCheckbox, MatCheckboxChange} from "@angular/material/checkbox";
|
import {MatCheckbox, MatCheckboxChange} from "@angular/material/checkbox";
|
||||||
import {EventRegistration, TournamentRegistration} from "../../model/tournamentRegistration";
|
import {EventRegistration, TournamentRegistration} from "../../model/tournamentRegistration";
|
||||||
import {MatOption} from "@angular/material/core";
|
import {MatOption} from "@angular/material/core";
|
||||||
import {MatSelect} from "@angular/material/select";
|
|
||||||
import {MatIcon} from "@angular/material/icon";
|
import {MatIcon} from "@angular/material/icon";
|
||||||
import {MatAnchor, MatButton} from "@angular/material/button";
|
import {MatAnchor, MatButton} from "@angular/material/button";
|
||||||
import {MatSnackBar} from "@angular/material/snack-bar";
|
import {MatSnackBar} from "@angular/material/snack-bar";
|
||||||
import {FullNamePipe} from "../../pipes/fullname-pipe";
|
import {FullNamePipe} from "../../pipes/fullname-pipe";
|
||||||
import {HeaderService} from "../../service/header.service";
|
import {HeaderService} from "../../service/header.service";
|
||||||
|
import {MatAutocomplete, MatAutocompleteTrigger} from "@angular/material/autocomplete";
|
||||||
|
import {MatInput} from "@angular/material/input";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-player-registrations',
|
selector: 'app-player-registrations',
|
||||||
@@ -30,11 +31,14 @@ import {HeaderService} from "../../service/header.service";
|
|||||||
MatCardActions,
|
MatCardActions,
|
||||||
RouterLink,
|
RouterLink,
|
||||||
MatOption,
|
MatOption,
|
||||||
MatSelect,
|
// MatSelect,
|
||||||
MatIcon,
|
MatIcon,
|
||||||
MatButton,
|
MatButton,
|
||||||
MatAnchor,
|
MatAnchor,
|
||||||
FullNamePipe
|
FullNamePipe,
|
||||||
|
MatAutocomplete,
|
||||||
|
MatAutocompleteTrigger,
|
||||||
|
MatInput,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
FullNamePipe
|
FullNamePipe
|
||||||
@@ -52,6 +56,8 @@ export class PlayerRegistrationsComponent implements OnInit {
|
|||||||
|
|
||||||
waitingForBackend: boolean = false;
|
waitingForBackend: boolean = false;
|
||||||
|
|
||||||
|
private partnerSearchTerms: Map<number, string> = new Map();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _snackBar: MatSnackBar,
|
private _snackBar: MatSnackBar,
|
||||||
private playerService: PlayerService,
|
private playerService: PlayerService,
|
||||||
@@ -76,6 +82,40 @@ export class PlayerRegistrationsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPartnerSearch(searchTerm: any, eventRegistration: EventRegistration) {
|
||||||
|
// Only treat as search if it's a string (typed input)
|
||||||
|
if (typeof searchTerm === 'string') {
|
||||||
|
this.partnerSearchTerms.set(eventRegistration.id, searchTerm?.toLowerCase() || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilteredPlayers(eventRegistration: EventRegistration): Player[] {
|
||||||
|
const allRelevant = this.getRelevantPlayers(eventRegistration.type);
|
||||||
|
const searchTerm = this.partnerSearchTerms.get(eventRegistration.id);
|
||||||
|
|
||||||
|
if (!searchTerm) {
|
||||||
|
return allRelevant;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allRelevant.filter(player => {
|
||||||
|
const fullName = this.fullNamePipe.transform(player).toLowerCase();
|
||||||
|
return fullName.includes(searchTerm);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
displayPartnerName(playerId: number | null): string {
|
||||||
|
if (!playerId || !this.allPlayers) return '';
|
||||||
|
const player = this.allPlayers.find(p => p.id === playerId);
|
||||||
|
return player ? this.fullNamePipe.transform(player) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
onPartnerSelected(event: any, eventRegistration: EventRegistration) {
|
||||||
|
eventRegistration.partner = event.option.value;
|
||||||
|
// Clear the search term when a partner is selected
|
||||||
|
this.partnerSearchTerms.delete(eventRegistration.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
saveRegistration(tournamentRegistration: TournamentRegistration, event: MouseEvent) {
|
saveRegistration(tournamentRegistration: TournamentRegistration, event: MouseEvent) {
|
||||||
this.waitingForBackend = true;
|
this.waitingForBackend = true;
|
||||||
this.registrationService.saveTournamentRegistrations(tournamentRegistration, this.player.id).subscribe(data => {
|
this.registrationService.saveTournamentRegistrations(tournamentRegistration, this.player.id).subscribe(data => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
[team]="match.team1"
|
[team]="match.team1"
|
||||||
[event]="this.event"
|
[event]="this.event"
|
||||||
[tournament]="this.tournament"
|
[tournament]="this.tournament"
|
||||||
[inline]="false">
|
[inline]="true">
|
||||||
</app-team-display>
|
</app-team-display>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle w-sep">-</td>
|
<td class="align-middle w-sep">-</td>
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -320,18 +323,31 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="align-middle w-fill">
|
<td class="align-middle w-fill">
|
||||||
@if (match.status == 'NOT_STARTED') {
|
@if (match.status == 'NOT_STARTED') {
|
||||||
|
@if (match.canStart) {
|
||||||
<button mat-button (click)="startMatch(match)">
|
<button mat-button (click)="startMatch(match)">
|
||||||
<mat-icon>play_arrow</mat-icon>
|
<mat-icon>play_arrow</mat-icon>
|
||||||
Wedstrijd starten
|
Wedstrijd starten
|
||||||
</button>
|
</button>
|
||||||
|
} @else {
|
||||||
|
<span [matTooltip]="match.cantStartReason" style="cursor: not-allowed;">
|
||||||
|
<button mat-button disabled>
|
||||||
|
<mat-icon>play_arrow</mat-icon>
|
||||||
|
Wedstrijd starten
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
} @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 +363,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 +445,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 ) {
|
||||||
|
|||||||
@@ -33,8 +33,10 @@ import {Standings} from "../../model/standings";
|
|||||||
import {HeaderService} from "../../service/header.service";
|
import {HeaderService} from "../../service/header.service";
|
||||||
import {TournamentPlayersComponent} from "../tournament-players/tournament-players.component";
|
import {TournamentPlayersComponent} from "../tournament-players/tournament-players.component";
|
||||||
import {TournamentPlayer} from "../../model/tournamentPlayer";
|
import {TournamentPlayer} from "../../model/tournamentPlayer";
|
||||||
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";
|
||||||
|
import {Observable, Subscription, tap} from "rxjs";
|
||||||
|
import {MatTooltip} from '@angular/material/tooltip';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tournament-manage',
|
selector: 'app-tournament-manage',
|
||||||
@@ -65,6 +67,7 @@ import {TeamDisplayComponent} from "../team-display/team-display.component";
|
|||||||
TournamentPlayersComponent,
|
TournamentPlayersComponent,
|
||||||
MatExpansionPanelActionRow,
|
MatExpansionPanelActionRow,
|
||||||
TeamDisplayComponent,
|
TeamDisplayComponent,
|
||||||
|
MatTooltip,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
FullNamePipe,
|
FullNamePipe,
|
||||||
@@ -97,10 +100,10 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
|
|||||||
this.activeRoundTab = params['tab'];
|
this.activeRoundTab = params['tab'];
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.tournamentService.getById(Number(id)).subscribe(data => {
|
this.loadTournament(
|
||||||
this.tournament = data;
|
this.tournamentService.getById(Number(id)),
|
||||||
this.headerService.setTitle(this.tournament.name);
|
(tournament) => this.headerService.setTitle(tournament.name)
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@@ -151,56 +154,42 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startRound(round: Round) {
|
startRound(round: Round) {
|
||||||
this.tournamentService.startRound(this.tournament.id, round.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.startRound(this.tournament.id, round.id));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finishRound(round: Round) {
|
finishRound(round: Round) {
|
||||||
this.tournamentService.finishRound(this.tournament.id, round.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.finishRound(this.tournament.id, round.id));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finishGroup(group: Group) {
|
finishGroup(group: Group) {
|
||||||
this.tournamentService.finishGroup(this.tournament.id, group.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.finishGroup(this.tournament.id, group.id));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reopenGroup(group: Group) {
|
reopenGroup(group: Group) {
|
||||||
this.tournamentService.reopenGroup(this.tournament.id, group.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.reopenGroup(this.tournament.id, group.id));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
divideTournament() {
|
divideTournament() {
|
||||||
this.tournamentService.divide(this.tournament.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.divide(this.tournament.id));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearDivision() {
|
clearDivision() {
|
||||||
this.tournamentService.clearDivision(this.tournament.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.clearDivision(this.tournament.id));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawTournament() {
|
drawTournament() {
|
||||||
this.tournamentService.draw(this.tournament.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.draw(this.tournament.id));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startMatch(match: Match) {
|
startMatch(match: Match) {
|
||||||
const availableCourts = this.getAvailableCourts();
|
const availableCourts = this.getAvailableCourts();
|
||||||
|
|
||||||
if (availableCourts.length == 0) {
|
if (availableCourts.length == 0) {
|
||||||
alert('Geen banen beschikbaar!');
|
this._snackBar.open('Geen banen beschikbaar.')
|
||||||
} else if (this.matchContainsPlayersThatArePlaying(match)) {
|
} else if (this.matchContainsPlayersThatArePlaying(match)) {
|
||||||
alert('Deze wedstrijd bevat spelers die al aan het spelen zijn!');
|
this._snackBar.open('Deze wedstrijd bevat spelers die al aan het spelen zijn.')
|
||||||
} else if (this.matchContainsPlayersThatAreCounting(match)) {
|
} else if (this.matchContainsPlayersThatAreCounting(match)) {
|
||||||
alert('Deze wedstrijd bevat spelers die aan het tellen zijn!');
|
this._snackBar.open('Deze wedstrijd bevat spelers die aan het tellen zijn.')
|
||||||
} else {
|
} else {
|
||||||
this.courtSelectionDialog.open(CourtSelectionComponent, {
|
this.courtSelectionDialog.open(CourtSelectionComponent, {
|
||||||
data: {
|
data: {
|
||||||
@@ -213,9 +202,7 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
|
|||||||
minHeight: '250px'
|
minHeight: '250px'
|
||||||
}).afterClosed().subscribe(result => {
|
}).afterClosed().subscribe(result => {
|
||||||
if (result != undefined) {
|
if (result != undefined) {
|
||||||
this.tournamentService.startMatch(this.tournament.id, match.id, result.court, result.counter.playerId).subscribe(data => {
|
this.loadTournament(this.tournamentService.startMatch(this.tournament.id, match.id, result.court, result.counter.playerId));
|
||||||
this.tournament = data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -223,26 +210,48 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
matchContainsPlayersThatArePlaying(match: Match): boolean {
|
matchContainsPlayersThatArePlaying(match: Match): boolean {
|
||||||
let matchPlayers: number[] = [];
|
let matchPlayers: number[] = [];
|
||||||
matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team1.player1).id);
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player1, match.type).id);
|
||||||
if (match.team1.player2) matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team1.player2).id);
|
if (match.team1.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player2, match.type).id);
|
||||||
matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team2.player1).id);
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player1, match.type).id);
|
||||||
if (match.team2.player2) matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team2.player2).id);
|
if (match.team2.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player2, match.type).id);
|
||||||
|
|
||||||
let matchPlayersThatArePlaying = this.tournament.playersPlaying.filter(Set.prototype.has, new Set(matchPlayers));
|
let matchPlayersThatArePlaying = this.tournament.playersPlaying.filter(Set.prototype.has, new Set(matchPlayers));
|
||||||
return matchPlayersThatArePlaying.length > 0;
|
return matchPlayersThatArePlaying.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matchPlayersThatArePlaying(match: Match): number[] {
|
||||||
|
let matchPlayers: number[] = [];
|
||||||
|
|
||||||
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player1, match.type).id);
|
||||||
|
if (match.team1.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player2, match.type).id);
|
||||||
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player1, match.type).id);
|
||||||
|
if (match.team2.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player2, match.type).id);
|
||||||
|
|
||||||
|
return this.tournament.playersPlaying.filter(Set.prototype.has, new Set(matchPlayers));
|
||||||
|
}
|
||||||
|
|
||||||
matchContainsPlayersThatAreCounting(match: Match): boolean {
|
matchContainsPlayersThatAreCounting(match: Match): boolean {
|
||||||
let matchPlayers: number[] = [];
|
let matchPlayers: number[] = [];
|
||||||
matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team1.player1).id);
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player1, match.type).id);
|
||||||
if (match.team1.player2) matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team1.player2).id);
|
if (match.team1.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player2, match.type).id);
|
||||||
matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team2.player1).id);
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player1, match.type).id);
|
||||||
if (match.team2.player2) matchPlayers.push(this.getTournamentPlayerFromPlayer(match.team2.player2).id);
|
if (match.team2.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player2, match.type).id);
|
||||||
|
|
||||||
let matchPlayersThatAreCounting = this.tournament.playersCounting.filter(Set.prototype.has, new Set(matchPlayers));
|
let matchPlayersThatAreCounting = this.tournament.playersCounting.filter(Set.prototype.has, new Set(matchPlayers));
|
||||||
return matchPlayersThatAreCounting.length > 0;
|
return matchPlayersThatAreCounting.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matchPlayersThatAreCounting(match: Match): number[] {
|
||||||
|
let matchPlayers: number[] = [];
|
||||||
|
|
||||||
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player1, match.type).id);
|
||||||
|
if (match.team1.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team1.player2, match.type).id);
|
||||||
|
matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player1, match.type).id);
|
||||||
|
if (match.team2.player2) matchPlayers.push(this.getPlayerOrSubstitute(match.team2.player2, match.type).id);
|
||||||
|
|
||||||
|
return this.tournament.playersCounting.filter(Set.prototype.has, new Set(matchPlayers));
|
||||||
|
}
|
||||||
|
|
||||||
getTournamentPlayerFromPlayer(player: Player): TournamentPlayer {
|
getTournamentPlayerFromPlayer(player: Player): TournamentPlayer {
|
||||||
for (let tournamentPlayer of this.tournament.tournamentPlayers) {
|
for (let tournamentPlayer of this.tournament.tournamentPlayers) {
|
||||||
if (tournamentPlayer.playerId == player.id) {
|
if (tournamentPlayer.playerId == player.id) {
|
||||||
@@ -302,15 +311,11 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stopMatch(match: Match) {
|
stopMatch(match: Match) {
|
||||||
this.tournamentService.stopMatch(this.tournament.id, match.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.stopMatch(this.tournament.id, match.id));
|
||||||
this.tournament = data;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newRound(group: Group) {
|
newRound(group: Group) {
|
||||||
this.tournamentService.newRound(this.tournament.id, group.id).subscribe(data => {
|
this.loadTournament(this.tournamentService.newRound(this.tournament.id, group.id));
|
||||||
this.tournament = data;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStrength(strength: string | undefined) {
|
getStrength(strength: string | undefined) {
|
||||||
@@ -367,6 +372,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, {
|
||||||
@@ -374,9 +380,7 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
|
|||||||
minWidth: '800px'
|
minWidth: '800px'
|
||||||
}).afterClosed().subscribe(result => {
|
}).afterClosed().subscribe(result => {
|
||||||
if (result != undefined) {
|
if (result != undefined) {
|
||||||
this.tournamentService.saveResult(this.tournament.id, result.matchId, result).subscribe(data => {
|
this.loadTournament(this.tournamentService.saveResult(this.tournament.id, result.matchId, result));
|
||||||
this.tournament = data;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -427,6 +431,84 @@ 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.loadTournament(this.tournamentService.updateCounter(this.tournament.id, match.id, result.counter.playerId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadTournament(
|
||||||
|
observable: Observable<Tournament>,
|
||||||
|
afterLoad?: (tournament: Tournament) => void
|
||||||
|
): Subscription {
|
||||||
|
return observable.subscribe(data => {
|
||||||
|
this.tournament = data;
|
||||||
|
this.updateMatchAvailability();
|
||||||
|
afterLoad?.(data); // Optional chaining
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateMatchAvailability() {
|
||||||
|
for (const event of this.tournament.events) {
|
||||||
|
for (const group of event.groups) {
|
||||||
|
for (const round of group.rounds) {
|
||||||
|
for (const match of round.matches) {
|
||||||
|
let canStart = true;
|
||||||
|
let matchPlayersThatArePlaying = this.matchPlayersThatArePlaying(match);
|
||||||
|
let matchPlayersThatAreCounting = this.matchPlayersThatAreCounting(match);
|
||||||
|
|
||||||
|
let cantStartReason = "";
|
||||||
|
|
||||||
|
if (matchPlayersThatArePlaying.length > 0) {
|
||||||
|
canStart = false;
|
||||||
|
cantStartReason = this.joinWithEn(matchPlayersThatArePlaying.map(m => this.getTournamentPlayerFromId(m).name));
|
||||||
|
if (matchPlayersThatArePlaying.length == 1) {
|
||||||
|
cantStartReason += " is al aan het spelen";
|
||||||
|
} else {
|
||||||
|
cantStartReason += " zijn al aan het spelen";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchPlayersThatAreCounting.length > 0) {
|
||||||
|
canStart = false;
|
||||||
|
if (cantStartReason.length > 0) {
|
||||||
|
cantStartReason += " en ";
|
||||||
|
}
|
||||||
|
cantStartReason += this.joinWithEn(matchPlayersThatAreCounting.map(m => this.getTournamentPlayerFromId(m).name));
|
||||||
|
if (matchPlayersThatAreCounting.length == 1) {
|
||||||
|
cantStartReason += " is aan het tellen";
|
||||||
|
} else {
|
||||||
|
cantStartReason += " zijn aan het tellen";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match.canStart = canStart;
|
||||||
|
match.cantStartReason = cantStartReason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
joinWithEn(items: string[], separator = ", "): string {
|
||||||
|
const len = items.length;
|
||||||
|
|
||||||
|
if (len === 0) return "";
|
||||||
|
if (len === 1) return items[0];
|
||||||
|
if (len === 2) return items.join(" en ");
|
||||||
|
|
||||||
|
return items.slice(0, -1).join(separator) + `${separator}and ${items[len - 1]}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActiveMatch {
|
class ActiveMatch {
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ import {Component, inject, Input, OnInit} from '@angular/core';
|
|||||||
import {CurrencyPipe} from "@angular/common";
|
import {CurrencyPipe} from "@angular/common";
|
||||||
import {MatSlideToggle, MatSlideToggleChange} from "@angular/material/slide-toggle";
|
import {MatSlideToggle, MatSlideToggleChange} from "@angular/material/slide-toggle";
|
||||||
import {TournamentService} from "../../service/tournament.service";
|
import {TournamentService} from "../../service/tournament.service";
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
import {ActivatedRoute} from "@angular/router";
|
||||||
import {Tournament} from "../../model/tournament";
|
import {Tournament} from "../../model/tournament";
|
||||||
import {FormsModule} from "@angular/forms";
|
import {FormsModule} from "@angular/forms";
|
||||||
import {MatSnackBar} from "@angular/material/snack-bar";
|
import {MatSnackBar} from "@angular/material/snack-bar";
|
||||||
import {MatIcon} from "@angular/material/icon";
|
import {MatIcon} from "@angular/material/icon";
|
||||||
import {MatIconButton} from "@angular/material/button";
|
import {MatIconButton} from "@angular/material/button";
|
||||||
import {MatMenu, MatMenuItem, MatMenuTrigger} from "@angular/material/menu";
|
import {MatMenu, MatMenuItem, MatMenuTrigger} from "@angular/material/menu";
|
||||||
import {CourtSelectionComponent} from "../court-selection/court-selection.component";
|
|
||||||
import {MatDialog} from "@angular/material/dialog";
|
import {MatDialog} from "@angular/material/dialog";
|
||||||
import {SubstituteSelectionComponent} from "../substitute-selection/substitute-selection.component";
|
import {SubstituteSelectionComponent} from "../substitute-selection/substitute-selection.component";
|
||||||
import {TournamentPlayer} from "../../model/tournamentPlayer";
|
import {TournamentPlayer} from "../../model/tournamentPlayer";
|
||||||
@@ -34,15 +33,27 @@ import {MatTab, MatTabGroup, MatTabLabel} from "@angular/material/tabs";
|
|||||||
standalone: true,
|
standalone: true,
|
||||||
styleUrl: './tournament-players.component.scss'
|
styleUrl: './tournament-players.component.scss'
|
||||||
})
|
})
|
||||||
export class TournamentPlayersComponent {
|
export class TournamentPlayersComponent implements OnInit {
|
||||||
|
|
||||||
@Input() tournament: Tournament;
|
@Input() tournament: Tournament;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private tournamentService: TournamentService,
|
private tournamentService: TournamentService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
private _snackBar: MatSnackBar,
|
private _snackBar: MatSnackBar,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (!this.tournament) {
|
||||||
|
const id = Number(this.route.snapshot.paramMap.get('id'));
|
||||||
|
if (id) {
|
||||||
|
this.tournamentService.getById(Number(id)).subscribe(data => {
|
||||||
|
this.tournament = data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
playerPaid($event: MatSlideToggleChange, playerId: number) {
|
playerPaid($event: MatSlideToggleChange, playerId: number) {
|
||||||
this.tournamentService.playerPaid(this.tournament.id, playerId, $event.checked).subscribe(() => {
|
this.tournamentService.playerPaid(this.tournament.id, playerId, $event.checked).subscribe(() => {
|
||||||
this._snackBar.open('Opgeslagen.');
|
this._snackBar.open('Opgeslagen.');
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ export class Match {
|
|||||||
games: Game[];
|
games: Game[];
|
||||||
court: number;
|
court: number;
|
||||||
counter: Player;
|
counter: Player;
|
||||||
|
canStart?: boolean;
|
||||||
|
cantStartReason?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,3 +7,6 @@ body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
|||||||
z-index: 2000 !important;
|
z-index: 2000 !important;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
.mat-tooltip {
|
||||||
|
white-space: pre-line !important;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user