Compare commits

...

3 Commits

Author SHA1 Message Date
Michel ten Voorde
3008f45dfa Use autocompletion for partner search
All checks were successful
Gitea/swiss-client/pipeline/head This commit looks good
2025-10-31 16:02:15 +01:00
Michel ten Voorde
5baf1228f7 Use autocompletion for partner search, WIP 2025-10-31 15:13:22 +01:00
Michel ten Voorde
aacf06e203 Made tournament-players more standalone, now works from tournament screen 2025-10-29 17:27:32 +01:00
3 changed files with 70 additions and 10 deletions

View File

@@ -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>

View File

@@ -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 => {

View File

@@ -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.');