Files
Pivot/templates/sgr_groepen.html
T
2026-10-14 12:29:29 +02:00

152 lines
8.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% 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 %}