425 lines
15 KiB
HTML
425 lines
15 KiB
HTML
<a routerLink="/schools" class="back-link">← Alle dansscholen</a>
|
||
@if (loading()) {
|
||
<div class="loading-state" role="status"><span class="spinner"></span> Dansschool laden…</div>
|
||
} @else if (!data()) {
|
||
<div class="empty-state">
|
||
<h1>Dansschool niet beschikbaar</h1>
|
||
<p role="alert">{{ error() }}</p>
|
||
<button type="button" class="button secondary" (click)="retry()">Opnieuw proberen</button>
|
||
</div>
|
||
} @else if (data(); as context) {
|
||
<div class="page-heading school-heading">
|
||
<div class="school-title">
|
||
<span aria-hidden="true" class="avatar large">{{
|
||
context.school.name.charAt(0).toUpperCase()
|
||
}}</span>
|
||
<div>
|
||
<p class="eyebrow">MIJN DANSSCHOOL</p>
|
||
<h1>{{ context.school.name }}</h1>
|
||
<p class="lede">Jouw dansers. Jouw ritme. Jouw podium.</p>
|
||
</div>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
class="button secondary"
|
||
(click)="editor.set({ kind: 'school', value: context.school })"
|
||
>
|
||
School bewerken
|
||
</button>
|
||
</div>
|
||
<app-school-transfer [schoolId]="context.school.id" (imported)="reload()" />
|
||
<nav class="tabs" aria-label="Dansschool onderdelen">
|
||
@for (tab of tabs; track tab.value) {
|
||
<a
|
||
[routerLink]="['/schools', context.school.id, tab.value]"
|
||
routerLinkActive="active"
|
||
ariaCurrentWhenActive="page"
|
||
>{{ tab.label }}
|
||
@switch (tab.value) {
|
||
@case ('dancers') {
|
||
<span>{{ context.dancers.length }}</span>
|
||
}
|
||
@case ('groups') {
|
||
<span>{{ context.groups.length }}</span>
|
||
}
|
||
@case ('shows') {
|
||
<span>{{ context.shows.length }}</span>
|
||
}
|
||
}
|
||
</a>
|
||
}
|
||
</nav>
|
||
@if (notice()) {
|
||
<div class="alert success" role="status">
|
||
{{ notice()
|
||
}}<button type="button" aria-label="Melding sluiten" (click)="notice.set('')">×</button>
|
||
</div>
|
||
}
|
||
@if (error()) {
|
||
<div class="alert error" role="alert">
|
||
{{ error()
|
||
}}<button type="button" class="button secondary" (click)="reload()">Vernieuwen</button>
|
||
</div>
|
||
}
|
||
@switch (section()) {
|
||
@case ('overview') {
|
||
<div class="stats-grid">
|
||
<a class="stat" [routerLink]="['/schools', context.school.id, 'dancers']"
|
||
><span class="stat-label">Dansers <span aria-hidden="true">↗</span></span
|
||
><strong>{{ context.dancers.length }}</strong
|
||
><span class="stat-caption">Alle talenten bij elkaar</span></a
|
||
>
|
||
<a class="stat" [routerLink]="['/schools', context.school.id, 'groups']"
|
||
><span class="stat-label">Dansgroepen <span aria-hidden="true">↗</span></span
|
||
><strong>{{ context.groups.length }}</strong
|
||
><span class="stat-caption">Samen de vloer op</span></a
|
||
>
|
||
<a class="stat" [routerLink]="['/schools', context.school.id, 'shows']"
|
||
><span class="stat-label">Shows <span aria-hidden="true">↗</span></span
|
||
><strong>{{ context.shows.length }}</strong
|
||
><span class="stat-caption">Momenten om naar uit te kijken</span></a
|
||
>
|
||
</div>
|
||
<div class="overview-grid">
|
||
<section class="panel">
|
||
<p class="eyebrow">DE VOLGENDE STAP</p>
|
||
<h2>Breng je school in beweging</h2>
|
||
<p class="muted">Een goede show begint in de studio. Zorg dat iedereen een plek heeft.</p>
|
||
<div class="quick-actions">
|
||
<button type="button" (click)="editor.set({ kind: 'dancer' })">
|
||
<span class="step-number">01</span
|
||
><span
|
||
><strong>Voeg een danser toe</strong
|
||
><small>Maak ruimte voor nieuw talent</small></span
|
||
><span aria-hidden="true">+</span>
|
||
</button>
|
||
<button type="button" (click)="editor.set({ kind: 'group' })">
|
||
<span class="step-number">02</span
|
||
><span
|
||
><strong>Stel een dansgroep samen</strong
|
||
><small>Verbind dansers met dezelfde passie</small></span
|
||
><span aria-hidden="true">+</span>
|
||
</button>
|
||
<button type="button" (click)="editor.set({ kind: 'show' })">
|
||
<span class="step-number">03</span
|
||
><span
|
||
><strong>Plan een show</strong
|
||
><small>Zet het volgende podium op de kalender</small></span
|
||
><span aria-hidden="true">+</span>
|
||
</button>
|
||
</div>
|
||
</section>
|
||
<section class="show-spotlight">
|
||
<div class="spotlight-decoration" aria-hidden="true">✳</div>
|
||
<p class="eyebrow">IN DE SPOTLIGHT</p>
|
||
@if (upcoming(); as show) {
|
||
<h2>{{ show.name }}</h2>
|
||
<p class="spotlight-date">{{ show.date | date: 'd MMMM yyyy' }}</p>
|
||
<p>Drie dagdelen. Eén gedeelde passie.</p>
|
||
<a class="button light" [routerLink]="['/schools', context.school.id, 'shows']"
|
||
>Shows bekijken <span aria-hidden="true">→</span></a
|
||
>
|
||
} @else {
|
||
<h2>Klaar voor<br />het grote podium?</h2>
|
||
<p>Maak een show aan en geef je dansers iets om naartoe te werken.</p>
|
||
<button type="button" class="button light" (click)="editor.set({ kind: 'show' })">
|
||
Eerste show plannen <span aria-hidden="true">→</span>
|
||
</button>
|
||
}
|
||
</section>
|
||
</div>
|
||
<section class="danger-zone">
|
||
<div>
|
||
<h3>Dansschool verwijderen</h3>
|
||
<p>Verwijdert ook alle dansers, groepen en shows van deze school.</p>
|
||
</div>
|
||
<button
|
||
class="button danger-outline"
|
||
type="button"
|
||
(click)="
|
||
askDelete({
|
||
kind: 'school',
|
||
id: context.school.id,
|
||
name: context.school.name,
|
||
explanation:
|
||
'Alle dansers, dansgroepen en shows van deze school worden ook definitief verwijderd.',
|
||
})
|
||
"
|
||
>
|
||
School verwijderen
|
||
</button>
|
||
</section>
|
||
}
|
||
@case ('dancers') {
|
||
<div class="section-heading">
|
||
<div>
|
||
<h2>Dansers</h2>
|
||
<p class="muted">De mensen die jouw school in beweging brengen.</p>
|
||
</div>
|
||
<button type="button" class="button primary" (click)="editor.set({ kind: 'dancer' })">
|
||
+ Danser toevoegen
|
||
</button>
|
||
</div>
|
||
@if (context.dancers.length) {
|
||
<label class="search-field"
|
||
><span aria-hidden="true">⌕</span
|
||
><input
|
||
type="search"
|
||
aria-label="Zoek een danser"
|
||
placeholder="Zoek op naam…"
|
||
[value]="search()"
|
||
(input)="search.set($any($event.target).value)"
|
||
/></label>
|
||
}
|
||
<div class="table-container">
|
||
<table>
|
||
<caption class="sr-only">
|
||
Dansers in
|
||
{{
|
||
context.school.name
|
||
}}
|
||
</caption>
|
||
<thead>
|
||
<tr>
|
||
<th>Danser</th>
|
||
<th>Geboortedatum</th>
|
||
<th>Dansgroepen</th>
|
||
<th><span class="sr-only">Acties</span></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (dancer of dancers(); track dancer.id) {
|
||
<tr>
|
||
<td>
|
||
<div class="person">
|
||
<span aria-hidden="true" class="avatar small">{{
|
||
dancer.name.charAt(0).toUpperCase()
|
||
}}</span
|
||
><strong>{{ dancer.name }}</strong>
|
||
</div>
|
||
</td>
|
||
<td class="nowrap">{{ dancer.birthDate | date: 'd MMM yyyy' }}</td>
|
||
<td class="muted">{{ groupNames(dancer.id) }}</td>
|
||
<td>
|
||
<div class="row-actions">
|
||
<button
|
||
class="text-button"
|
||
type="button"
|
||
[attr.aria-label]="dancer.name + ' bewerken'"
|
||
(click)="editor.set({ kind: 'dancer', value: dancer })"
|
||
>
|
||
Bewerken</button
|
||
><button
|
||
class="text-button destructive"
|
||
type="button"
|
||
[attr.aria-label]="dancer.name + ' verwijderen'"
|
||
(click)="
|
||
askDelete({
|
||
kind: 'dancer',
|
||
id: dancer.id,
|
||
name: dancer.name,
|
||
explanation:
|
||
'De danser wordt ook uit alle dansgroepen van deze school verwijderd.',
|
||
})
|
||
"
|
||
>
|
||
Verwijderen
|
||
</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
} @empty {
|
||
<tr>
|
||
<td colspan="4">
|
||
<div class="empty-state">
|
||
<h3>{{ search() ? 'Geen dansers gevonden' : 'De dansvloer is nog leeg' }}</h3>
|
||
<p>
|
||
{{
|
||
search()
|
||
? 'Probeer een andere naam.'
|
||
: 'Voeg je eerste danser toe. Daarna kun je die aan één of meerdere groepen koppelen.'
|
||
}}
|
||
</p>
|
||
@if (!search()) {
|
||
<button
|
||
class="button primary"
|
||
type="button"
|
||
(click)="editor.set({ kind: 'dancer' })"
|
||
>
|
||
Danser toevoegen
|
||
</button>
|
||
}
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
}
|
||
@case ('groups') {
|
||
<div class="section-heading">
|
||
<div>
|
||
<h2>Dansgroepen</h2>
|
||
<p class="muted">Iedere groep een eigen stijl. Iedere danser een plek.</p>
|
||
</div>
|
||
<button class="button primary" type="button" (click)="editor.set({ kind: 'group' })">
|
||
+ Dansgroep toevoegen
|
||
</button>
|
||
</div>
|
||
<div class="school-grid">
|
||
@for (group of context.groups; track group.id) {
|
||
<article class="group-card">
|
||
<div class="card-top">
|
||
<span class="group-symbol" aria-hidden="true">↗</span
|
||
><span class="tag">{{ groupType(group.type) }}</span>
|
||
</div>
|
||
<h3>{{ group.category }}</h3>
|
||
<p class="muted">
|
||
{{ group.startAge }}–{{ group.endAge }} jaar · {{ group.dancerIds.length }} dansers
|
||
</p>
|
||
<div class="tag-list">
|
||
@for (style of group.styles; track style) {
|
||
<span class="style-tag">{{ groupStyle(style) }}</span>
|
||
} @empty {
|
||
<span class="muted">Nog geen dansstijlen</span>
|
||
}
|
||
</div>
|
||
<button
|
||
class="button secondary full-width"
|
||
type="button"
|
||
[attr.aria-label]="'Dansers beheren voor ' + group.category"
|
||
(click)="members.set(group)"
|
||
>
|
||
Dansers beheren <span aria-hidden="true">→</span>
|
||
</button>
|
||
<div class="card-bottom">
|
||
<button
|
||
class="text-button"
|
||
type="button"
|
||
[attr.aria-label]="group.category + ' bewerken'"
|
||
(click)="editor.set({ kind: 'group', value: group })"
|
||
>
|
||
Bewerken</button
|
||
><button
|
||
class="text-button destructive"
|
||
type="button"
|
||
[attr.aria-label]="group.category + ' verwijderen'"
|
||
(click)="
|
||
askDelete({
|
||
kind: 'group',
|
||
id: group.id,
|
||
name: group.category,
|
||
explanation:
|
||
'De groep wordt verwijderd. De dansers blijven beschikbaar in de school.',
|
||
})
|
||
"
|
||
>
|
||
Verwijderen
|
||
</button>
|
||
</div>
|
||
</article>
|
||
} @empty {
|
||
<div class="empty-state full-width">
|
||
<span class="empty-symbol" aria-hidden="true">↗</span>
|
||
<h2>Samen vind je het ritme</h2>
|
||
<p>Maak een dansgroep aan en koppel er dansers aan.</p>
|
||
<button class="button primary" type="button" (click)="editor.set({ kind: 'group' })">
|
||
Eerste dansgroep aanmaken
|
||
</button>
|
||
</div>
|
||
}
|
||
</div>
|
||
}
|
||
@case ('shows') {
|
||
<div class="section-heading">
|
||
<div>
|
||
<h2>Shows</h2>
|
||
<p class="muted">Van maanden oefenen naar een onvergetelijk optreden.</p>
|
||
</div>
|
||
<button class="button primary" type="button" (click)="editor.set({ kind: 'show' })">
|
||
+ Show toevoegen
|
||
</button>
|
||
</div>
|
||
<div class="show-list">
|
||
@for (show of shows(); track show.id) {
|
||
<article class="show-card">
|
||
<div class="date-tile">
|
||
<strong>{{ show.date | date: 'dd' }}</strong
|
||
><span>{{ show.date | date: 'MMM yyyy' }}</span>
|
||
</div>
|
||
<div class="show-details">
|
||
<h3>{{ show.name }}</h3>
|
||
<div class="tag-list">
|
||
<span class="style-tag">Ochtend</span><span class="style-tag">Middag</span
|
||
><span class="style-tag">Avond</span>
|
||
</div>
|
||
<p class="muted">Groepen indelen over dagdelen is nog niet beschikbaar.</p>
|
||
</div>
|
||
<div class="row-actions">
|
||
<button
|
||
class="text-button"
|
||
type="button"
|
||
[attr.aria-label]="show.name + ' bewerken'"
|
||
(click)="editor.set({ kind: 'show', value: show })"
|
||
>
|
||
Bewerken</button
|
||
><button
|
||
class="text-button destructive"
|
||
type="button"
|
||
[attr.aria-label]="show.name + ' verwijderen'"
|
||
(click)="
|
||
askDelete({
|
||
kind: 'show',
|
||
id: show.id,
|
||
name: show.name,
|
||
explanation: 'Deze show wordt definitief verwijderd.',
|
||
})
|
||
"
|
||
>
|
||
Verwijderen
|
||
</button>
|
||
</div>
|
||
</article>
|
||
} @empty {
|
||
<div class="empty-state">
|
||
<span class="empty-symbol" aria-hidden="true">✦</span>
|
||
<h2>Het podium wacht op je</h2>
|
||
<p>Plan een show met een ochtend-, middag- en avonddeel.</p>
|
||
<button class="button primary" type="button" (click)="editor.set({ kind: 'show' })">
|
||
Eerste show plannen
|
||
</button>
|
||
</div>
|
||
}
|
||
</div>
|
||
}
|
||
}
|
||
@if (editor(); as target) {
|
||
<app-entity-editor
|
||
[target]="target"
|
||
[schoolId]="context.school.id"
|
||
(closed)="editor.set(null)"
|
||
(saved)="saved()"
|
||
/>
|
||
}
|
||
@if (members(); as group) {
|
||
<app-group-members
|
||
[group]="group"
|
||
[schoolId]="context.school.id"
|
||
[dancers]="context.dancers"
|
||
(closed)="members.set(null)"
|
||
(changed)="membershipChanged($event)"
|
||
/>
|
||
}
|
||
@if (deleting(); as target) {
|
||
<app-confirm-dialog
|
||
[name]="target.name"
|
||
[explanation]="target.explanation"
|
||
[busy]="deleteBusy()"
|
||
[error]="deleteError()"
|
||
(closed)="deleting.set(null)"
|
||
(confirmed)="confirmDelete()"
|
||
/>
|
||
}
|
||
}
|