import { Component, inject, input, output, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
import { apiError } from '../core/api-error';
interface Preview {
name: string;
dancers: number;
groups: number;
shows: number;
existingId: number | null;
existingName: string | null;
existingRevision: number | null;
}
@Component({
selector: 'app-school-transfer',
template: `
@if (schoolId() !== undefined) {
}
@if (error()) {
{{ error() }}
}
@if (notice()) {
{{ notice() }}
}
@if (preview(); as p) {
{{ p.name }}
{{ p.dancers }} dansers · {{ p.groups }} dansgroepen · {{ p.shows }} shows
@if (p.existingId !== null) {
De bestaande school {{ p.existingName }} wordt volledig vervangen. Alle huidige gegevens
van deze school verdwijnen.
} @else {
}
}
`,
})
export class SchoolTransfer {
readonly schoolId = input();
readonly imported = output();
private readonly http = inject(HttpClient);
readonly preview = signal(null);
readonly busy = signal(false);
readonly error = signal('');
readonly notice = signal('');
private json = '';
private readonly base = '/api/dance-schools';
cancel(): void {
this.preview.set(null);
this.json = '';
this.notice.set('');
}
async select(event: Event): Promise {
const input = event.target as HTMLInputElement;
const file = input.files?.[0];
input.value = '';
this.cancel();
this.error.set('');
if (!file) return;
this.busy.set(true);
try {
this.json = await file.text();
this.preview.set(
await firstValueFrom(
this.http.post(`${this.base}/import/preview`, this.json, {
headers: { 'Content-Type': 'application/json' },
}),
),
);
} catch (e) {
this.error.set(
`Import niet gelukt: ${e instanceof Error && !('status' in e) ? e.message : apiError(e)}`,
);
} finally {
this.busy.set(false);
}
}
async confirm(): Promise {
const p = this.preview();
if (!p || this.busy()) return;
this.busy.set(true);
this.error.set('');
try {
const query = p.existingId === null ? '' : `?replaceId=${p.existingId}`;
await firstValueFrom(
this.http.post(`${this.base}/import${query}`, this.json, {
headers: {
'Content-Type': 'application/json',
...(p.existingRevision === null
? {}
: { 'X-School-Revision': String(p.existingRevision) }),
},
}),
);
this.cancel();
this.notice.set('School geïmporteerd.');
this.imported.emit();
} catch (e) {
this.error.set(`Import niet gelukt: ${apiError(e)}`);
this.preview.set(null);
} finally {
this.busy.set(false);
}
}
async download(): Promise {
this.error.set('');
this.busy.set(true);
try {
const blob = await firstValueFrom(
this.http.get(`${this.base}/${this.schoolId()}/export`, { responseType: 'blob' }),
);
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `school-${this.schoolId()}.json`;
link.click();
setTimeout(() => URL.revokeObjectURL(url), 1000);
} catch (e) {
this.error.set(`Export niet gelukt: ${apiError(e)}`);
} finally {
this.busy.set(false);
}
}
}