import { Component, computed, DestroyRef, inject, OnInit, signal } from '@angular/core'; import { DatePipe } from '@angular/common'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ActivatedRoute, Router, RouterLink, RouterLinkActive } from '@angular/router'; import { catchError, EMPTY, firstValueFrom, switchMap } from 'rxjs'; import { DanceGroup, EditorTarget, GROUP_STYLES, GROUP_TYPES, ResourceKind, SchoolData, } from '../core/api-models'; import { apiError } from '../core/api-error'; import { SchoolApi } from '../core/school-api'; import { EntityEditor } from '../shared/entity-editor'; import { ConfirmDialog } from '../shared/confirm-dialog'; import { GroupMembers } from '../shared/group-members'; interface DeleteTarget { kind: ResourceKind; id: number; name: string; explanation: string; } @Component({ selector: 'app-school-page', imports: [DatePipe, RouterLink, RouterLinkActive, EntityEditor, ConfirmDialog, GroupMembers], templateUrl: './school-page.html', }) export class SchoolPage implements OnInit { private readonly api = inject(SchoolApi); private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); private readonly destroyRef = inject(DestroyRef); readonly data = signal(null); readonly section = signal('overview'); readonly loading = signal(true); readonly error = signal(''); readonly notice = signal(''); readonly editor = signal(null); readonly members = signal(null); readonly deleting = signal(null); readonly deleteBusy = signal(false); readonly deleteError = signal(''); readonly search = signal(''); readonly dancers = computed(() => [...(this.data()?.dancers ?? [])] .filter((d) => d.name.toLocaleLowerCase('nl').includes(this.search().toLocaleLowerCase('nl'))) .sort((a, b) => a.name.localeCompare(b.name, 'nl')), ); readonly shows = computed(() => [...(this.data()?.shows ?? [])].sort((a, b) => a.date.localeCompare(b.date)), ); readonly today = new Date().toLocaleDateString('en-CA'); readonly upcoming = computed(() => this.shows().find((show) => show.date >= this.today)); readonly tabs = [ { value: 'overview', label: 'Overzicht' }, { value: 'dancers', label: 'Dansers' }, { value: 'groups', label: 'Dansgroepen' }, { value: 'shows', label: 'Shows' }, ]; ngOnInit(): void { this.route.paramMap .pipe( switchMap((params) => { this.loading.set(true); this.error.set(''); this.search.set(''); this.editor.set(null); this.members.set(null); this.deleting.set(null); this.section.set(params.get('section') ?? 'overview'); return this.api.schoolData(Number(params.get('schoolId'))).pipe( catchError((error) => { this.data.set(null); this.error.set(apiError(error)); this.loading.set(false); return EMPTY; }), ); }), takeUntilDestroyed(this.destroyRef), ) .subscribe((data) => { this.data.set(data); this.loading.set(false); }); } async reload(): Promise { const id = this.data()?.school.id; if (id === undefined) return; this.error.set(''); try { const data = await firstValueFrom(this.api.schoolData(id)); if (this.data()?.school.id === id) this.data.set(data); } catch (error: unknown) { this.error.set(apiError(error)); } } retry(): void { window.location.reload(); } async saved(): Promise { this.editor.set(null); this.notice.set('Wijzigingen opgeslagen.'); await this.reload(); } groupType(value: string): string { return GROUP_TYPES.find((option) => option.value === value)?.label ?? value; } groupStyle(value: string): string { return GROUP_STYLES.find((option) => option.value === value)?.label ?? value; } groupNames(dancerId: number): string { return ( this.data() ?.groups.filter((group) => group.dancerIds.includes(dancerId)) .map((group) => group.category) .join(', ') || 'Nog geen groep' ); } askDelete(target: DeleteTarget): void { this.deleteError.set(''); this.deleting.set(target); } membershipChanged(ids: number[]): void { const groupId = this.members()?.id; this.data.update((data) => data ? { ...data, groups: data.groups.map((group) => group.id === groupId ? { ...group, dancerIds: [...ids] } : group, ), } : data, ); } async confirmDelete(): Promise { const target = this.deleting(); const schoolId = this.data()?.school.id; if (!target || schoolId === undefined || this.deleteBusy()) return; this.deleteBusy.set(true); this.deleteError.set(''); try { await firstValueFrom(this.api.delete(target.kind, schoolId, target.id)); this.deleting.set(null); if (target.kind === 'school') await this.router.navigate(['/schools']); else { this.notice.set(`${target.name} is verwijderd.`); await this.reload(); } } catch (error: unknown) { this.deleteError.set(apiError(error)); } finally { this.deleteBusy.set(false); } } }