All checks were successful
Gitea/swiss-client/pipeline/head This commit looks good
381 lines
11 KiB
TypeScript
381 lines
11 KiB
TypeScript
import {Component, inject, Input, OnInit} from '@angular/core';
|
|
import {
|
|
MatAccordion,
|
|
MatExpansionPanel,
|
|
MatExpansionPanelHeader,
|
|
MatExpansionPanelTitle
|
|
} from "@angular/material/expansion";
|
|
import {MatCard, MatCardContent, MatCardHeader} from "@angular/material/card";
|
|
import {CurrencyPipe, DatePipe, DecimalPipe, NgClass} from "@angular/common";
|
|
import {TeamPipe} from "../../pipes/team-pipe";
|
|
import {TournamentService} from "../../service/tournament.service";
|
|
import {ActivatedRoute, Router} from "@angular/router";
|
|
import {Tournament} from "../../model/tournament";
|
|
import {FullNamePipe} from "../../pipes/fullname-pipe";
|
|
import {MatButton, MatIconButton} from "@angular/material/button";
|
|
import {MatIcon} from "@angular/material/icon";
|
|
import {Group} from "../../model/group";
|
|
import {Round} from "../../model/round";
|
|
import {MatMenu, MatMenuContent, MatMenuItem, MatMenuTrigger} from "@angular/material/menu";
|
|
import {Match} from "../../model/match";
|
|
import {FormsModule} from "@angular/forms";
|
|
import {MatTab, MatTabChangeEvent, MatTabGroup, MatTabLabel} from "@angular/material/tabs";
|
|
import {MatchResultComponent} from "../match-result/match-result.component";
|
|
import {MatDialog} from "@angular/material/dialog";
|
|
import {MatchResultPipe} from "../../pipes/match-result-pipe";
|
|
import {Event} from "../../model/event";
|
|
import {TournamentValidateComponent} from "../tournament-validate/tournament-validate.component";
|
|
import {Strength} from "../../model/player";
|
|
import {MatSlideToggle, MatSlideToggleChange} from "@angular/material/slide-toggle";
|
|
import {MatSnackBar} from "@angular/material/snack-bar";
|
|
import {CourtSelectionComponent} from "../court-selection/court-selection.component";
|
|
import {Standings} from "../../model/standings";
|
|
import {Title} from '@angular/platform-browser';
|
|
import {TitleService} from "../../service/title.service";
|
|
|
|
@Component({
|
|
selector: 'app-tournament-manage',
|
|
imports: [
|
|
FullNamePipe,
|
|
MatAccordion,
|
|
MatCard,
|
|
MatCardContent,
|
|
MatCardHeader,
|
|
MatExpansionPanel,
|
|
MatExpansionPanelHeader,
|
|
MatExpansionPanelTitle,
|
|
TeamPipe,
|
|
MatIcon,
|
|
NgClass,
|
|
MatMenu,
|
|
MatMenuItem,
|
|
MatMenuTrigger,
|
|
FormsModule,
|
|
DatePipe,
|
|
MatTabGroup,
|
|
MatTab,
|
|
MatTabLabel,
|
|
MatButton,
|
|
MatIconButton,
|
|
DecimalPipe,
|
|
TournamentValidateComponent,
|
|
MatSlideToggle,
|
|
CurrencyPipe,
|
|
MatMenuContent
|
|
],
|
|
providers: [
|
|
FullNamePipe,
|
|
TeamPipe,
|
|
MatchResultPipe
|
|
],
|
|
templateUrl: './tournament-manage.component.html',
|
|
styleUrl: './tournament-manage.component.scss'
|
|
})
|
|
export class TournamentManageComponent implements OnInit {
|
|
|
|
@Input() tournament: Tournament;
|
|
|
|
activeRoundTab: number = 0;
|
|
|
|
constructor(
|
|
private tournamentService: TournamentService,
|
|
private _snackBar: MatSnackBar,
|
|
private route: ActivatedRoute,
|
|
private router: Router,
|
|
private titleService: TitleService,
|
|
private title: Title
|
|
) {
|
|
}
|
|
|
|
ngOnInit() {
|
|
const id = this.route.snapshot.paramMap.get('id');
|
|
this.route.queryParams.subscribe(params => {
|
|
if (params['tab']) {
|
|
this.activeRoundTab = params['tab'];
|
|
}
|
|
})
|
|
this.tournamentService.getById(Number(id)).subscribe(data => {
|
|
this.tournament = data;
|
|
this.titleService.setTitle(this.tournament.name);
|
|
this.title.setTitle(this.tournament.name);
|
|
});
|
|
}
|
|
|
|
onRoundTabChange(event: MatTabChangeEvent) {
|
|
const index = event.index;
|
|
this.router.navigate(
|
|
['tournaments/' + this.tournament.id + '/manage'],
|
|
{
|
|
relativeTo: null, queryParams: {tab: index}
|
|
});
|
|
}
|
|
|
|
getRoundIcon(status: String) {
|
|
if (status == "FINISHED") {
|
|
return "check";
|
|
} else if (status == "IN_PROGRESS") {
|
|
return "play_arrow";
|
|
} else if (status == "NOT_STARTED") {
|
|
return "hourglass_top";
|
|
} else {
|
|
return "warning";
|
|
}
|
|
}
|
|
|
|
getStandingsForRound(round: Round, group: Group): Standings {
|
|
if (round.status == 'FINISHED') {
|
|
return round.standings;
|
|
} else {
|
|
return group.standings;
|
|
}
|
|
}
|
|
|
|
groupIsDoublesType(group: Group) {
|
|
return group.type == 'HD' || group.type == 'DD' || group.type == 'GD';
|
|
}
|
|
|
|
startRound(round: Round) {
|
|
this.tournamentService.startRound(this.tournament.id, round.id).subscribe(data => {
|
|
this.tournament = data;
|
|
});
|
|
}
|
|
|
|
finishRound(round: Round) {
|
|
this.tournamentService.finishRound(this.tournament.id, round.id).subscribe(data => {
|
|
this.tournament = data;
|
|
});
|
|
}
|
|
|
|
finishGroup(group: Group) {
|
|
this.tournamentService.finishGroup(this.tournament.id, group.id).subscribe(data => {
|
|
this.tournament = data;
|
|
});
|
|
}
|
|
reopenGroup(group: Group) {
|
|
this.tournamentService.reopenGroup(this.tournament.id, group.id).subscribe(data => {
|
|
this.tournament = data;
|
|
});
|
|
}
|
|
|
|
divideTournament() {
|
|
this.tournamentService.divide(this.tournament.id).subscribe(data => {
|
|
this.tournament = data;
|
|
});
|
|
}
|
|
|
|
clearDivision() {
|
|
this.tournamentService.clearDivision(this.tournament.id).subscribe(data => {
|
|
this.tournament = data;
|
|
});
|
|
}
|
|
|
|
drawTournament() {
|
|
this.tournamentService.draw(this.tournament.id).subscribe(data => {
|
|
this.tournament = data;
|
|
});
|
|
}
|
|
|
|
startMatch(match: Match) {
|
|
const availableCourts = this.getAvailableCourts();
|
|
|
|
if (availableCourts.length == 0) {
|
|
alert('Geen banen beschikbaar!');
|
|
} else if (this.matchContainsPlayersThatArePlaying(match)) {
|
|
alert('Deze wedstrijd bevat spelers die al aan het spelen zijn!');
|
|
} else {
|
|
this.courtSelectionDialog.open(CourtSelectionComponent, {
|
|
data: {
|
|
match: match,
|
|
availableCourts: this.getAvailableCourts(),
|
|
totalCourts: this.tournament.courts
|
|
},
|
|
minWidth: '800px',
|
|
minHeight: '250px'
|
|
}).afterClosed().subscribe(result => {
|
|
if (result != undefined) {
|
|
this.tournamentService.startMatch(this.tournament.id, match.id, result).subscribe(data => {
|
|
this.tournament = data;
|
|
})
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
matchContainsPlayersThatArePlaying(match: Match): boolean {
|
|
let activePlayers: number[] = [];
|
|
for (let activeMatch of this.activeMatches()) {
|
|
activePlayers.push(activeMatch.match.team1.player1.id);
|
|
if (activeMatch.match.team1.player2) activePlayers.push(activeMatch.match.team1.player2.id);
|
|
activePlayers.push(activeMatch.match.team2.player1.id);
|
|
if (activeMatch.match.team2.player2) activePlayers.push(activeMatch.match.team2.player2.id);
|
|
}
|
|
let matchPlayers: number[] = [];
|
|
matchPlayers.push(match.team1.player1.id);
|
|
if (match.team1.player2) matchPlayers.push(match.team1.player2.id);
|
|
matchPlayers.push(match.team2.player1.id);
|
|
if (match.team2.player2) matchPlayers.push(match.team2.player2.id);
|
|
let playersThatArePlaying = activePlayers.filter(Set.prototype.has, new Set(matchPlayers));
|
|
return playersThatArePlaying.length > 0;
|
|
}
|
|
|
|
getAvailableCourts(): number[] {
|
|
const maxCourts = this.tournament.courts;
|
|
const activeCourts = this.activeMatches().map(activeMatch => activeMatch.match.court);
|
|
|
|
let i = 0, courts = Array(maxCourts);
|
|
while (i < maxCourts) courts[i++] = i;
|
|
|
|
return courts.filter(court => activeCourts.indexOf(court) < 0);
|
|
}
|
|
|
|
stopMatch(match: Match) {
|
|
this.tournamentService.stopMatch(this.tournament.id, match.id).subscribe(data => {
|
|
this.tournament = data;
|
|
})
|
|
}
|
|
|
|
newRound(group: Group) {
|
|
this.tournamentService.newRound(this.tournament.id, group.id).subscribe(data => {
|
|
this.tournament = data;
|
|
})
|
|
}
|
|
|
|
playerPaid($event: MatSlideToggleChange, playerId: number) {
|
|
this.tournamentService.playerPaid(this.tournament.id, playerId, $event.checked).subscribe(() => {
|
|
this._snackBar.open('Opgeslagen.');
|
|
});
|
|
}
|
|
|
|
playerPresent($event: MatSlideToggleChange, playerId: number) {
|
|
this.tournamentService.playerPresent(this.tournament.id, playerId, $event.checked).subscribe(() => {
|
|
this._snackBar.open('Opgeslagen.');
|
|
});
|
|
}
|
|
|
|
getStrength(strength: string | undefined) {
|
|
if (strength == undefined) return "";
|
|
for (let [key, value] of Object.entries(Strength)) {
|
|
if (key == strength) return value;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
printMatchSheets(round: Round) {
|
|
window.open(`tournaments/${this.tournament.id}/rounds/${round.id}/matchsheets`, "_blank");
|
|
}
|
|
|
|
printRoundOverview(round: Round) {
|
|
window.open(`tournaments/${this.tournament.id}/rounds/${round.id}/overview`, "_blank");
|
|
}
|
|
|
|
activeMatches(): ActiveMatch[] {
|
|
let matches: ActiveMatch[] = [];
|
|
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) {
|
|
if (match.status == 'IN_PROGRESS') {
|
|
matches.push(new ActiveMatch(match, round, group));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return matches;
|
|
}
|
|
|
|
getActiveMatchCountForGroup(group: Group): number {
|
|
let active = 0;
|
|
for (const round of group.rounds) {
|
|
for (const match of round.matches) {
|
|
if (match.status == 'IN_PROGRESS') {
|
|
active++;
|
|
}
|
|
}
|
|
}
|
|
return active;
|
|
}
|
|
|
|
groupOnlyHasFinishedRounds(group: Group): boolean {
|
|
let allFinished = true;
|
|
for (const round of group.rounds) {
|
|
allFinished &&= round.status == 'FINISHED';
|
|
}
|
|
return allFinished;
|
|
}
|
|
|
|
matchResultDialog = inject(MatDialog);
|
|
courtSelectionDialog = inject(MatDialog);
|
|
|
|
editResult(match: Match, group: Group, round: Round) {
|
|
this.matchResultDialog.open(MatchResultComponent, {
|
|
data: {match: match, group: group, round: round},
|
|
minWidth: '800px'
|
|
}).afterClosed().subscribe(result => {
|
|
if (result != undefined) {
|
|
this.tournamentService.saveResult(this.tournament.id, result.matchId, result).subscribe(data => {
|
|
this.tournament = data;
|
|
})
|
|
}
|
|
});
|
|
}
|
|
|
|
checkWinner(match: Match): number {
|
|
if (match.games.length == 0) return 0;
|
|
if (match.games.length == 3) {
|
|
if (match.games[2].score1 > match.games[2].score2) {
|
|
return 1;
|
|
} else {
|
|
return 2;
|
|
}
|
|
}
|
|
if (match.games[1].score1 > match.games[1].score2) {
|
|
return 1;
|
|
} else {
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
checkRoundComplete(round: Round) {
|
|
let complete: boolean = true;
|
|
for (let match of round.matches) {
|
|
complete &&= match.status == 'FINISHED';
|
|
}
|
|
|
|
return complete;
|
|
}
|
|
|
|
protected readonly TournamentEvent = Event;
|
|
|
|
getEventMatchCount(event: Event) {
|
|
let count = 0;
|
|
for (let group of event.groups) {
|
|
let numTeams = group.teams.length;
|
|
let rounds = numTeams <= 4 ? 3 : 4;
|
|
let matchesPerRound = Math.trunc(numTeams / 2);
|
|
count += (rounds * matchesPerRound);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
getTournamentMatchCount(tournament: Tournament) {
|
|
let count = 0;
|
|
for (let event of tournament.events) {
|
|
count += this.getEventMatchCount(event);
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
class ActiveMatch {
|
|
constructor(match: Match, round: Round, group: Group) {
|
|
this.match = match;
|
|
this.round = round;
|
|
this.group = group;
|
|
}
|
|
|
|
match: Match;
|
|
round: Round;
|
|
group: Group;
|
|
}
|