167 lines
9.0 KiB
HTML
167 lines
9.0 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Verzendlijsten{% endblock %}
|
||
{% block page_title %}Verzendlijsten{% endblock %}
|
||
{% block loader_text %}Verzendlijsten ophalen bij Google...{% endblock %}
|
||
|
||
{% block extra_css %}
|
||
<style>
|
||
.nieuw-grid { display: grid; grid-template-columns: 1.4fr 1.2fr 1.6fr; gap: 12px; align-items: end; }
|
||
.nieuw-grid .breed { grid-column: 1 / -1; }
|
||
.nieuw-grid .field { margin: 0; }
|
||
.adres-veld { display: flex; align-items: stretch; }
|
||
.adres-veld input { border-top-right-radius: 0; border-bottom-right-radius: 0; flex: 1; min-width: 0; }
|
||
.adres-veld select, .adres-veld .at { border-top-left-radius: 0; border-bottom-left-radius: 0; }
|
||
.adres-veld .at { display: grid; place-items: center; padding: 0 8px; background: var(--surface-muted);
|
||
border: 1px solid var(--border); border-left: 0; border-right: 0; color: var(--text-muted); }
|
||
.adres-veld select { width: auto; max-width: 55%; }
|
||
@media (max-width: 760px) { .nieuw-grid { grid-template-columns: 1fr; } }
|
||
details.nieuw > summary { cursor: pointer; list-style: none; display: inline-flex; }
|
||
details.nieuw > summary::-webkit-details-marker { display: none; }
|
||
details.nieuw[open] > summary { margin-bottom: 14px; }
|
||
.zoekbalk { display: flex; gap: 10px; margin-bottom: 12px; }
|
||
.zoekbalk input { flex: 1; }
|
||
th.sorteer { cursor: pointer; user-select: none; white-space: nowrap; }
|
||
th.sorteer:hover { color: var(--primary-color); }
|
||
th.sorteer .pijl::after { content: "↕"; opacity: .35; margin-left: 2px; }
|
||
th.sorteer.op .pijl::after { content: "▲"; opacity: 1; }
|
||
th.sorteer.af .pijl::after { content: "▼"; opacity: 1; }
|
||
.tabel-voet { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; margin-top: 12px; }
|
||
.paginering { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
||
td.mail { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .88em; }
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="card">
|
||
<details class="nieuw" {% if not lijsten and not fout %}open{% endif %}>
|
||
<summary class="btn btn-success">➕ Nieuwe verzendlijst</summary>
|
||
<form method="POST" action="{{ url_for('verzendlijsten.nieuw') }}" class="nieuw-grid" onsubmit="showLoader('Verzendlijst aanmaken...')">
|
||
<div class="field">
|
||
<label for="adres">E-mailadres</label>
|
||
<div class="adres-veld">
|
||
<input type="text" id="adres" name="adres" required placeholder="bv. leerkrachten-1ste-graad" autocomplete="off">
|
||
{% if domeinen %}
|
||
<span class="at">@</span>
|
||
<select name="domein" aria-label="Domein">
|
||
{% for d in domeinen %}<option>{{ d }}</option>{% endfor %}
|
||
</select>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<label for="naam">Naam</label>
|
||
<input type="text" id="naam" name="naam" required placeholder="bv. Leerkrachten 1ste graad">
|
||
</div>
|
||
<div class="field">
|
||
<label for="wie_mailt_n">Wie mag mailen naar de lijst?</label>
|
||
<select id="wie_mailt_n" name="wie_mailt">
|
||
<option value="">Standaard van Google</option>
|
||
{% for w, l in wie_mailt %}<option value="{{ w }}">{{ l }}</option>{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="field breed">
|
||
<label for="beschrijving">Beschrijving</label>
|
||
<input type="text" id="beschrijving" name="beschrijving" placeholder="Waarvoor dient deze lijst? (optioneel)">
|
||
</div>
|
||
<div class="breed"><button type="submit">💾 Verzendlijst aanmaken</button></div>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="page-head">
|
||
<h2>📮 Verzendlijsten</h2>
|
||
<a class="btn btn-light btn-sm" href="{{ url_for('verzendlijsten.overzicht') }}" onclick="showLoader()">🔄 Vernieuwen</a>
|
||
</div>
|
||
|
||
{% if fout %}
|
||
<div class="alert alert-danger">{{ fout }}</div>
|
||
{% else %}
|
||
<div class="zoekbalk">
|
||
<input type="search" id="zoek" placeholder="Zoek op naam, adres of beschrijving..." aria-label="Zoeken">
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th class="sorteer" data-kol="0">Naam <span class="pijl"></span></th>
|
||
<th class="sorteer" data-kol="1">E-mailadres <span class="pijl"></span></th>
|
||
<th class="sorteer text-right" data-kol="2">Leden <span class="pijl"></span></th>
|
||
<th class="sorteer" data-kol="3">Beschrijving <span class="pijl"></span></th>
|
||
<th class="actions"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="lijstBody">
|
||
{% for g in lijsten %}
|
||
<tr data-zoek="{{ [g.naam, g.email, g.beschrijving]|join(' ')|lower }}">
|
||
<td data-sort="{{ g.naam }}"><strong>{{ g.naam }}</strong></td>
|
||
<td class="mail" data-sort="{{ g.email }}">{{ g.email }}{% if g.aliassen %}<br><span class="muted small">ook: {{ g.aliassen|join(', ') }}</span>{% endif %}</td>
|
||
<td class="text-right" data-sort="{{ '%06d'|format(g.leden) }}">{{ g.leden }}</td>
|
||
<td class="muted small" data-sort="{{ g.beschrijving }}">{{ g.beschrijving }}</td>
|
||
<td class="actions"><a class="btn btn-sm btn-secondary" href="{{ url_for('verzendlijsten.detail', email=g.email) }}" onclick="showLoader('Leden ophalen...')">✏️ Openen</a></td>
|
||
</tr>
|
||
{% else %}
|
||
<tr class="empty-row"><td colspan="5">Er zijn nog geen verzendlijsten in Google.</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="tabel-voet">
|
||
<div style="display:flex;align-items:center;gap:14px;flex-wrap:wrap">
|
||
<div class="muted small" id="teller"></div>
|
||
<span id="perPagina"></span>
|
||
</div>
|
||
<nav class="paginering" id="paginering" aria-label="Pagina's"></nav>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
(function () {
|
||
const body = document.getElementById('lijstBody');
|
||
if (!body || body.querySelector('.empty-row')) return;
|
||
let PER_PAGINA = perPagina('verzendlijsten'), pagina = 1, kol = null, op = true, zoek = '';
|
||
const zichtbaar = () => Array.from(body.rows).filter(tr => !zoek || tr.dataset.zoek.includes(zoek));
|
||
function toon() {
|
||
const rijen = zichtbaar(), grootte = PER_PAGINA || Infinity;
|
||
const paginas = Math.max(1, Math.ceil(rijen.length / grootte));
|
||
pagina = Math.min(Math.max(1, pagina), paginas);
|
||
const van = PER_PAGINA ? (pagina - 1) * PER_PAGINA : 0, tot = van + grootte;
|
||
Array.from(body.rows).forEach(tr => tr.style.display = 'none');
|
||
rijen.forEach((tr, i) => tr.style.display = (i >= van && i < tot) ? '' : 'none');
|
||
document.getElementById('teller').textContent = rijen.length
|
||
? `${van + 1}–${Math.min(tot, rijen.length)} van ${rijen.length} verzendlijst(en)` : 'Geen verzendlijsten gevonden';
|
||
const nav = document.getElementById('paginering');
|
||
nav.innerHTML = '';
|
||
if (paginas <= 1) return;
|
||
const knop = (label, p, actief) => {
|
||
const b = document.createElement('button');
|
||
b.type = 'button'; b.textContent = label; b.className = 'btn-sm ' + (actief ? 'btn-secondary' : 'btn-light');
|
||
b.onclick = () => { pagina = p; toon(); };
|
||
nav.appendChild(b);
|
||
};
|
||
if (pagina > 1) { knop('«', 1); knop('‹ Vorige', pagina - 1); }
|
||
for (let p = Math.max(1, pagina - 2); p <= Math.min(paginas, pagina + 2); p++) knop(String(p), p, p === pagina);
|
||
if (pagina < paginas) { knop('Volgende ›', pagina + 1); knop('»', paginas); }
|
||
}
|
||
document.getElementById('zoek').addEventListener('input', e => { zoek = e.target.value.trim().toLowerCase(); pagina = 1; toon(); });
|
||
document.querySelectorAll('th.sorteer').forEach(th => th.addEventListener('click', () => {
|
||
const k = +th.dataset.kol;
|
||
op = kol === k ? !op : (k !== 2); kol = k;
|
||
document.querySelectorAll('th.sorteer').forEach(x => x.classList.remove('op', 'af'));
|
||
th.classList.add(op ? 'op' : 'af');
|
||
Array.from(body.rows).sort((a, b) => {
|
||
const c = (a.cells[k].dataset.sort || '').localeCompare(b.cells[k].dataset.sort || '', 'nl', { numeric: true, sensitivity: 'base' });
|
||
return op ? c : -c;
|
||
}).forEach(tr => body.appendChild(tr));
|
||
pagina = 1; toon();
|
||
}));
|
||
perPaginaKiezer(document.getElementById('perPagina'), 'verzendlijsten', n => { PER_PAGINA = n; pagina = 1; toon(); });
|
||
toon();
|
||
})();
|
||
</script>
|
||
{% endblock %}
|