Compare commits

...

2 Commits

Author SHA1 Message Date
2c33c9a68d Invallers
All checks were successful
Gitea/swiss-client/pipeline/head This commit looks good
2025-09-23 22:45:44 +02:00
181aebf16a Invallers 2025-09-23 20:47:11 +02:00
11 changed files with 145 additions and 31 deletions

View File

@@ -32,11 +32,11 @@
Player-registrations: oude toernooien verbergen via knop Player-registrations: oude toernooien verbergen via knop
Onderdeel afsluiten Onderdeel afsluiten
Wedstrijd opgave Wedstrijd opgave
Blessures Invallers
Titels pagina's Titels pagina's
Authenticatie Authenticatie
Progress indicator tijdens communicatie backend Progress indicator tijdens communicatie backend
Bij tellers rekening houden met invallers
https://blog.shhdharmen.me/browser-storage-in-angular-ssr https://blog.shhdharmen.me/browser-storage-in-angular-ssr
Won't do / later: Won't do / later:

View File

@@ -0,0 +1,4 @@
.has-substitute {
text-decoration-line: underline;
text-decoration-style: dotted;
}

View File

@@ -0,0 +1,42 @@
import {Component, Input} from '@angular/core';
import {Player} from '../../model/player';
import {Event} from '../../model/event';
import {Tournament} from '../../model/tournament';
import {FullNamePipe} from '../../pipes/fullname-pipe';
import {MatTooltip} from '@angular/material/tooltip';
@Component({
selector: 'app-player-display',
standalone: true,
imports: [FullNamePipe, MatTooltip],
styleUrls: ['./player-display.component.scss'],
template: `
@let substitute = getSubstituteForEvent(player, event);
<span [class.has-substitute]="substitute"
[matTooltip]="substitute ? 'Valt in voor ' + (player | fullName) : ''"
matTooltipPosition="below">
{{ substitute || (player | fullName) }}
</span>
`
})
export class PlayerDisplayComponent {
@Input({ required: true }) player!: Player;
@Input({ required: true }) event!: Event;
@Input({ required: true }) tournament!: Tournament;
getSubstituteForEvent(player: Player, event: Event): string | undefined {
const tournamentPlayer = this.tournament.tournamentPlayers.find(
tp => tp.playerId === player.id
);
if (!tournamentPlayer) return undefined;
const substitution = tournamentPlayer.substitutions.find(
s => s.event === event.type
);
if (!substitution) return undefined;
return this.tournament.tournamentPlayers.find(
p => p.id === substitution.substitute
)?.name;
}
}

View File

@@ -0,0 +1,32 @@
import {Component, Input} from '@angular/core';
import {Event} from '../../model/event';
import {Tournament} from '../../model/tournament';
import {PlayerDisplayComponent} from '../player-display/player-display.component';
import {Team} from "../../model/team";
@Component({
selector: 'app-team-display',
standalone: true,
imports: [PlayerDisplayComponent],
template: `
<app-player-display
[player]="team.player1"
[event]="event"
[tournament]="tournament">
</app-player-display>
@if (event.doublesEvent && team.player2) {
/
<app-player-display
[player]="team.player2"
[event]="event"
[tournament]="tournament">
</app-player-display>
}
`
})
export class TeamDisplayComponent {
@Input({ required: true }) team!: Team;
@Input({ required: true }) event!: Event;
@Input({ required: true }) tournament!: Tournament;
}

View File

@@ -25,16 +25,8 @@
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
&nbsp;Beheer &nbsp;Beheer
</ng-template> </ng-template>
<mat-tab-group animationDuration="0ms" disableRipple="true">
<mat-tab>
<ng-template mat-tab-label>
<mat-icon>group</mat-icon>
&nbsp;Spelerslijst
</ng-template>
<app-tournament-players [tournament]="tournament"></app-tournament-players> <app-tournament-players [tournament]="tournament"></app-tournament-players>
</mat-tab> </mat-tab>
</mat-tab-group>
</mat-tab>
} }
@if (tournament.status == 'DIVIDED') { @if (tournament.status == 'DIVIDED') {
@@ -117,16 +109,8 @@
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
&nbsp;Beheer &nbsp;Beheer
</ng-template> </ng-template>
<mat-tab-group animationDuration="0ms" disableRipple="true">
<mat-tab>
<ng-template mat-tab-label>
<mat-icon>group</mat-icon>
&nbsp;Spelerslijst
</ng-template>
<app-tournament-players [tournament]="tournament"></app-tournament-players> <app-tournament-players [tournament]="tournament"></app-tournament-players>
</mat-tab> </mat-tab>
</mat-tab-group>
</mat-tab>
} }
@if (tournament.status == 'ONGOING') { @if (tournament.status == 'ONGOING') {
@@ -270,27 +254,54 @@
<tbody> <tbody>
@for (match of round.matches; track match.id) { @for (match of round.matches; track match.id) {
<tr> <tr>
<td class="align-middle w-team">{{ match.team1 | teamText }}</td> <td class="align-middle w-team">
<app-team-display
[team]="match.team1"
[event]="event"
[tournament]="tournament">
</app-team-display>
</td>
<td class="align-middle w-sep">-</td> <td class="align-middle w-sep">-</td>
<td class="align-middle w-team">{{ match.team2 | teamText }}</td> <td class="align-middle w-team">
<app-team-display
[team]="match.team2"
[event]="event"
[tournament]="tournament">
</app-team-display>
</td>
<td class="align-middle w-fill"></td> <td class="align-middle w-fill"></td>
</tr> </tr>
} }
@if (round.drawnOut) { @if (round.drawnOut) {
<tr> <tr>
<td class="align-middle w-100" colspan="4"><b>Deze ronde uitgeloot:</b> {{ round.drawnOut | teamText }}</td> <td class="align-middle w-100" colspan="4">
<b>Deze ronde uitgeloot:</b> {{ round.drawnOut | teamText }}
</td>
</tr> </tr>
} }
</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>
@for (match of round.matches; track match.id) { @for (match of round.matches; track match.id) {
<tr> <tr>
<td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 1}">{{ match.team1 | teamText }}</td> <td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 1}">
<app-team-display
[team]="match.team1"
[event]="event"
[tournament]="tournament">
</app-team-display>
</td>
<td class="align-middle w-sep">-</td> <td class="align-middle w-sep">-</td>
<td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 2}">{{ match.team2 | teamText }}</td> <td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 2}">
<app-team-display
[team]="match.team2"
[event]="event"
[tournament]="tournament">
</app-team-display>
</td>
<td class="align-middle w-fill"> <td class="align-middle w-fill">
@if (match.status == 'NOT_STARTED') { @if (match.status == 'NOT_STARTED') {
<button mat-button (click)="startMatch(match)"> <button mat-button (click)="startMatch(match)">
@@ -341,9 +352,21 @@
<tbody> <tbody>
@for (match of round.matches; track match.id) { @for (match of round.matches; track match.id) {
<tr> <tr>
<td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 1}">{{ match.team1 | teamText }}</td> <td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 1}">
<app-team-display
[team]="match.team1"
[event]="event"
[tournament]="tournament">
</app-team-display>
</td>
<td class="align-middle w-sep">-</td> <td class="align-middle w-sep">-</td>
<td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 2}">{{ match.team2 | teamText }}</td> <td class="align-middle w-team" [ngClass]="{'winner': checkWinner(match) == 2}">
<app-team-display
[team]="match.team2"
[event]="event"
[tournament]="tournament">
</app-team-display>
</td>
<td class="align-middle w-fill"> <td class="align-middle w-fill">
<div class="row result align-items-center"> <div class="row result align-items-center">
@for (game of match.games; track game.id) { @for (game of match.games; track game.id) {

View File

@@ -35,7 +35,7 @@ td.w-fill {
width: 95% !important; width: 95% !important;
} }
.mat-menu-panel { .mat-menu-panel {
z-index: 1000 !important; z-index: 1000 !important;
} }

View File

@@ -26,13 +26,15 @@ import {MatDialog} from "@angular/material/dialog";
import {MatchResultPipe} from "../../pipes/match-result-pipe"; import {MatchResultPipe} from "../../pipes/match-result-pipe";
import {Event} from "../../model/event"; import {Event} from "../../model/event";
import {TournamentValidateComponent} from "../tournament-validate/tournament-validate.component"; import {TournamentValidateComponent} from "../tournament-validate/tournament-validate.component";
import {Strength} from "../../model/player"; import {Player, Strength} from "../../model/player";
import {MatSnackBar} from "@angular/material/snack-bar"; import {MatSnackBar} from "@angular/material/snack-bar";
import {CourtSelectionComponent} from "../court-selection/court-selection.component"; import {CourtSelectionComponent} from "../court-selection/court-selection.component";
import {Standings} from "../../model/standings"; 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";
@Component({ @Component({
selector: 'app-tournament-manage', selector: 'app-tournament-manage',
@@ -62,6 +64,8 @@ import {TournamentPlayer} from "../../model/tournamentPlayer";
TournamentValidateComponent, TournamentValidateComponent,
TournamentPlayersComponent, TournamentPlayersComponent,
MatExpansionPanelActionRow, MatExpansionPanelActionRow,
MatTooltip,
TeamDisplayComponent,
], ],
providers: [ providers: [
FullNamePipe, FullNamePipe,
@@ -412,6 +416,7 @@ export class TournamentManageComponent implements OnInit, OnDestroy {
} }
return count; return count;
} }
} }
class ActiveMatch { class ActiveMatch {

View File

@@ -68,6 +68,7 @@
<th>Naam</th> <th>Naam</th>
<th>Wedstrijden geteld</th> <th>Wedstrijden geteld</th>
<th>Onderdelen</th> <th>Onderdelen</th>
<th>Invallers</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
@@ -81,6 +82,7 @@
{{ event }}&nbsp; {{ event }}&nbsp;
} }
</td> </td>
<td>{{ hasSubstitutes(tournamentPlayer) ? 'Ja' : 'Nee' }}</td>
<td> <td>
<button mat-icon-button [matMenuTriggerFor]="dividedTournamentMenu" class="menu-button"> <button mat-icon-button [matMenuTriggerFor]="dividedTournamentMenu" class="menu-button">
<mat-icon>more_vert</mat-icon> <mat-icon>more_vert</mat-icon>
@@ -88,7 +90,7 @@
<mat-menu #dividedTournamentMenu="matMenu"> <mat-menu #dividedTournamentMenu="matMenu">
<button mat-menu-item (click)="findSubstitute(tournamentPlayer)"> <button mat-menu-item (click)="findSubstitute(tournamentPlayer)">
<mat-icon>autorenew</mat-icon> <mat-icon>autorenew</mat-icon>
Invaller kiezen Invallers
</button> </button>
<button mat-menu-item> <!--(click)="drawTournament()"--> <button mat-menu-item> <!--(click)="drawTournament()"-->
<mat-icon>do_not_disturb_on</mat-icon> <mat-icon>do_not_disturb_on</mat-icon>

View File

@@ -1,3 +1,7 @@
td, th { td, th {
background-color: transparent !important; background-color: transparent !important;
} }
td {
vertical-align: middle;
}

View File

@@ -90,4 +90,7 @@ export class TournamentPlayersComponent implements OnInit {
} }
hasSubstitutes(tournamentPlayer: TournamentPlayer) {
return tournamentPlayer.substitutions.filter(s => s.substitute != null && s.substitute >= 0).length > 0;
}
} }

View File

@@ -14,6 +14,5 @@ export class TournamentPlayer {
export class TournamentPlayerSubstitution { export class TournamentPlayerSubstitution {
substitutionId: number; substitutionId: number;
event: string; event: string;
// substitute: TournamentPlayer;
substitute: number = -1; substitute: number = -1;
} }