import { SchedulingRun } from './scheduling-status'; import { inject, Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, tap } from 'rxjs'; import { Coach, DanceGroup, Dancer, DancerRequest, GroupRequest, ResourceKind, School, SchoolData, SchoolRequest, Show, ShowRequest, } from './api-models'; @Injectable({ providedIn: 'root' }) export class SchoolApi { private readonly http = inject(HttpClient); private readonly base = '/api/dance-schools'; private readonly revisions = new Map(); schools(): Observable { return this.http.get(this.base).pipe( tap((schools) => { for (const school of schools) this.revisions.set(school.id, school.revision); }), ); } schoolData(schoolId: number): Observable { return this.http .get(`${this.base}/${schoolId}/data`) .pipe(tap((data) => this.revisions.set(schoolId, data.school.revision))); } private options(schoolId: number, expected?: number): { headers: Record } { const revision = expected ?? this.revisions.get(schoolId); return { headers: revision === undefined ? {} : { 'X-School-Revision': String(revision) } }; } saveSchool(body: SchoolRequest, id?: number, revision?: number): Observable { return id === undefined ? this.http.post(this.base, body) : this.http.put(`${this.base}/${id}`, body, this.options(id, revision)); } saveDancer( schoolId: number, body: DancerRequest, id?: number, revision?: number, ): Observable { return this.save(`${this.base}/${schoolId}/dancers`, body, schoolId, id, revision); } saveGroup( schoolId: number, body: GroupRequest, id?: number, revision?: number, ): Observable { return this.save(`${this.base}/${schoolId}/dance-groups`, body, schoolId, id, revision); } saveShow(schoolId: number, body: ShowRequest, id?: number, revision?: number): Observable { return this.save(`${this.base}/${schoolId}/shows`, body, schoolId, id, revision); } schedule(schoolId: number, showId: number): Observable { return this.http.post( `${this.base}/${schoolId}/shows/${showId}/schedule`, null, this.options(schoolId), ); } saveAssignments( schoolId: number, showId: number, assignments: number[][], revision?: number, ): Observable { return this.http.put( `${this.base}/${schoolId}/shows/${showId}/assignments`, { assignments, }, this.options(schoolId, revision), ); } finalize(schoolId: number, showId: number, revision?: number): Observable { return this.http.post( `${this.base}/${schoolId}/shows/${showId}/finalize`, null, this.options(schoolId, revision), ); } linkCoach(schoolId: number, dancerId: number, coachId?: number): Observable { return this.save(`${this.base}/${schoolId}/coaches`, { dancerId }, schoolId, coachId); } unlinkCoach(schoolId: number, coachId: number): Observable { return this.http.delete( `${this.base}/${schoolId}/coaches/${coachId}/dancer`, this.options(schoolId), ); } delete(kind: ResourceKind, schoolId: number, id: number, revision?: number): Observable { const collection = { school: '', dancer: '/dancers', group: '/dance-groups', show: '/shows' }[ kind ]; const url = kind === 'school' ? `${this.base}/${id}` : `${this.base}/${schoolId}${collection}/${id}`; return this.http.delete(url, this.options(schoolId, revision)); } membership( schoolId: number, groupId: number, dancerId: number, add: boolean, revision?: number, ): Observable { const url = `${this.base}/${schoolId}/dance-groups/${groupId}/dancers/${dancerId}`; return add ? this.http.put(url, null, this.options(schoolId, revision)) : this.http.delete(url, this.options(schoolId, revision)); } private save( url: string, body: unknown, schoolId: number, id?: number, revision?: number, ): Observable { return id === undefined ? this.http.post(url, body, this.options(schoolId, revision)) : this.http.put(`${url}/${id}`, body, this.options(schoolId, revision)); } }