152 lines
8.9 KiB
HTML
152 lines
8.9 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}SGR groepen{% endblock %}
|
||
{% block page_title %}SGR groepen{% endblock %}
|
||
{% block main_class %}wide{% endblock %}
|
||
{% block loader_text %}Groepen ophalen uit Smartschool...{% endblock %}
|
||
|
||
{% block extra_css %}
|
||
<style>
|
||
.keuze { display: flex; gap: 8px; align-items: center; margin: 0; }
|
||
.keuze input { width: 240px; }
|
||
.tellers { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 6px; }
|
||
.tellers span { padding: 4px 12px; border-radius: 999px; background: var(--surface-muted); border: 1px solid var(--border); font-size: .88em; }
|
||
.tellers b { margin-left: 4px; }
|
||
.filter-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 12px 0; }
|
||
.filter-bar input[type=search] { flex: 0 1 340px; }
|
||
.groepen { display: grid; gap: 8px; }
|
||
details.groep { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface, #fff); }
|
||
details.groep[open] { border-color: var(--primary-color); }
|
||
details.groep > summary { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 10px 14px;
|
||
cursor: pointer; list-style: none; }
|
||
details.groep > summary::-webkit-details-marker { display: none; }
|
||
details.groep > summary::before { content: "▸"; color: var(--text-muted, #64748b); transition: transform .15s; }
|
||
details.groep[open] > summary::before { transform: rotate(90deg); }
|
||
.groep .gnaam { font-weight: 600; }
|
||
.groep .pad { font-size: .85em; color: var(--text-muted, #64748b); }
|
||
.groep .aantal { margin-left: auto; padding: 2px 10px; border-radius: 999px; background: var(--primary-light);
|
||
color: var(--primary-color); font-weight: 700; font-size: .88em; white-space: nowrap; }
|
||
.groep .aantal.leeg { background: var(--surface-muted); color: var(--text-muted, #64748b); font-weight: 400; }
|
||
.groep .inhoud { padding: 0 14px 12px; }
|
||
.groep table { margin: 0; }
|
||
.rol { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: .85em; background: var(--surface-muted); }
|
||
.rol.Leerling { background: #dbeafe; color: #1d4ed8; }
|
||
.rol.Leerkracht { background: #dcfce7; color: #15803d; }
|
||
mark { background: #fef08a; padding: 0; }
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="card">
|
||
<div class="page-head">
|
||
<h2>👥 SGR groep in Smartschool</h2>
|
||
<div class="actions">
|
||
<form method="GET" action="{{ url_for('sgr_groepen.overzicht') }}" class="keuze" onsubmit="showLoader()">
|
||
<input type="text" name="groep" value="{{ groep }}" aria-label="Hoofdgroep" title="Naam of code van de Smartschool-groep">
|
||
<button type="submit" class="btn-light btn-sm">Tonen</button>
|
||
</form>
|
||
{% if groepen %}<a class="btn btn-light btn-sm" href="{{ url_for('sgr_groepen.export', groep=groep if groep != standaard else None) }}">⬇️ CSV</a>{% endif %}
|
||
<a class="btn btn-secondary btn-sm" href="{{ url_for('sgr_groepen.overzicht', groep=groep if groep != standaard else None, vernieuw=1) }}" onclick="showLoader()">🔄 Opnieuw ophalen</a>
|
||
</div>
|
||
</div>
|
||
|
||
{% if fout %}
|
||
<div class="alert alert-danger">{{ fout }}</div>
|
||
{% elif not groepen %}
|
||
<p class="muted">De groep <strong>{{ hoofd.naam }}</strong> bestaat in Smartschool, maar heeft geen subgroepen.</p>
|
||
{% else %}
|
||
<div class="tellers">
|
||
<span>Subgroepen <b>{{ groepen|length }}</b></span>
|
||
<span title="Elk lidmaatschap apart geteld">Lidmaatschappen <b>{{ aantal_leden }}</b></span>
|
||
<span title="Wie in meer dan één groep zit, telt één keer">Verschillende personen <b>{{ uniek }}</b></span>
|
||
{% set leeg = groepen|selectattr('leden', 'equalto', [])|selectattr('fout', 'none')|list|length %}
|
||
{% if leeg %}<span>Zonder leden <b>{{ leeg }}</b></span>{% endif %}
|
||
</div>
|
||
<div class="filter-bar">
|
||
<input type="search" id="zoek" placeholder="Zoek een groep of een lid (naam, gebruikersnaam)..." aria-label="Zoeken">
|
||
<button type="button" class="btn-light btn-sm" id="allesOpen">Alles openklappen</button>
|
||
<button type="button" class="btn-light btn-sm" id="allesDicht">Alles dichtklappen</button>
|
||
<span class="muted small" id="zoekTeller"></span>
|
||
<span class="muted small">Opgehaald uit Smartschool op {{ opgehaald }}</span>
|
||
</div>
|
||
|
||
<div class="groepen" id="groepen">
|
||
{% for g in groepen %}
|
||
<details class="groep" style="margin-left: {{ g.diepte * 24 }}px" data-groep="{{ (g.naam ~ ' ' ~ g.code ~ ' ' ~ g.omschrijving)|lower }}">
|
||
<summary>
|
||
<span class="gnaam">{{ g.naam }}</span>
|
||
{% if g.code and g.code != g.naam %}<span class="muted small">{{ g.code }}</span>{% endif %}
|
||
{% if g.pad %}<span class="pad">in {{ g.pad|join(' › ') }}</span>{% endif %}
|
||
{% if g.fout %}
|
||
<span class="badge badge-danger" title="{{ g.fout }}">leden niet op te halen</span>
|
||
{% else %}
|
||
<span class="aantal {{ 'leeg' if not g.leden }}">{{ g.leden|length }} {{ 'lid' if g.leden|length == 1 else 'leden' }}{% if g.aantal_sub %} · {{ g.aantal_sub }} subgroep{{ 'en' if g.aantal_sub != 1 }}{% endif %}</span>
|
||
{% endif %}
|
||
</summary>
|
||
<div class="inhoud">
|
||
{% if g.omschrijving and g.omschrijving != g.naam %}<p class="muted small" style="margin:0 0 8px">{{ g.omschrijving }}</p>{% endif %}
|
||
{% if g.fout %}
|
||
<div class="alert alert-danger" style="margin:0">Leden konden niet opgehaald worden: {{ g.fout }}</div>
|
||
{% elif not g.leden %}
|
||
<p class="muted small" style="margin:0">Deze groep heeft momenteel geen rechtstreekse leden.</p>
|
||
{% else %}
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead><tr><th>Naam</th><th>Voornaam</th><th>Gebruikersnaam</th><th>Rol</th><th>E-mail</th></tr></thead>
|
||
<tbody>
|
||
{% for l in g.leden %}
|
||
<tr class="lid" data-tekst="{{ (l.naam ~ ' ' ~ l.voornaam ~ ' ' ~ l.voornaam ~ ' ' ~ l.naam ~ ' ' ~ l.gebruikersnaam ~ ' ' ~ l.email)|lower }}">
|
||
<td><strong>{{ l.naam }}</strong></td>
|
||
<td>{{ l.voornaam }}</td>
|
||
<td>{{ l.gebruikersnaam }}</td>
|
||
<td>{% if l.rol %}<span class="rol {{ l.rol }}">{{ l.rol }}</span>{% endif %}</td>
|
||
<td class="small">{{ l.email }}</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</details>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
<p class="field-hint" style="margin-top:14px">Toont alle groepen onder <strong>{{ groep }}</strong> in Smartschool met hun huidige,
|
||
rechtstreekse leden. De standaard hoofdgroep ({{ standaard }}) stel je in via 🔌 Koppelingen › Smartschool.
|
||
Gegevens worden 10 minuten bewaard.</p>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
(function () {
|
||
const lijst = document.getElementById('groepen');
|
||
if (!lijst) return;
|
||
const groepen = Array.from(lijst.querySelectorAll('details.groep'));
|
||
const zoekveld = document.getElementById('zoek'), teller = document.getElementById('zoekTeller');
|
||
document.getElementById('allesOpen').onclick = () => groepen.forEach(d => { if (d.style.display !== 'none') d.open = true; });
|
||
document.getElementById('allesDicht').onclick = () => groepen.forEach(d => d.open = false);
|
||
zoekveld.addEventListener('input', () => {
|
||
const z = zoekveld.value.trim().toLowerCase();
|
||
let treffers = 0, zichtbaar = 0;
|
||
groepen.forEach(d => {
|
||
const naamTreffer = !z || d.dataset.groep.includes(z);
|
||
let lidTreffer = 0;
|
||
d.querySelectorAll('tr.lid').forEach(tr => {
|
||
const ok = !z || naamTreffer || tr.dataset.tekst.includes(z);
|
||
tr.style.display = ok ? '' : 'none';
|
||
if (z && tr.dataset.tekst.includes(z)) lidTreffer++;
|
||
});
|
||
const toon = naamTreffer || lidTreffer > 0;
|
||
d.style.display = toon ? '' : 'none';
|
||
if (toon) zichtbaar++;
|
||
treffers += lidTreffer;
|
||
if (z) d.open = lidTreffer > 0;
|
||
});
|
||
teller.textContent = z ? `${zichtbaar} groep(en)` + (treffers ? `, ${treffers} lid/leden gevonden` : '') : '';
|
||
});
|
||
})();
|
||
</script>
|
||
{% endblock %}
|