feat: add CRUD functionality for classes with API endpoints and UI integration
All checks were successful
Build & Push / Build & Push image (push) Successful in 41s
All checks were successful
Build & Push / Build & Push image (push) Successful in 41s
This commit is contained in:
@@ -188,6 +188,9 @@
|
||||
<label>Status</label>
|
||||
<select id="filterStatus">
|
||||
<option value="all">Alle statussen</option>
|
||||
<option value="groen">✓ Minstens één groen</option>
|
||||
<option value="oranje">~ Minstens één oranje</option>
|
||||
<option value="roze">! Minstens één roze</option>
|
||||
<option value="consensus">✓ Consensus (iedereen groen)</option>
|
||||
<option value="verschil">⚠ Verschillen</option>
|
||||
<option value="niemand">○ Niemand beoordeeld</option>
|
||||
@@ -247,9 +250,12 @@
|
||||
<!-- TAB: Leerkrachten koppelen -->
|
||||
<div class="tab-content" id="tab-koppeling">
|
||||
<div class="card">
|
||||
<h2>👥 Leerkrachten aan klassen koppelen</h2>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem;flex-wrap:wrap;gap:.5rem;">
|
||||
<h2 style="margin:0;">👥 Klassen & Leerkrachten</h2>
|
||||
<button class="btn btn-primary" id="btnNieuweKlas">+ Klas toevoegen</button>
|
||||
</div>
|
||||
<p style="font-size:.85rem;color:var(--gray-500);margin-bottom:1rem;">
|
||||
Klik op een klas om de gekoppelde leerkrachten te wijzigen.
|
||||
Klik op een klas om leerkrachten te wijzigen. Gebruik het prullenbakje om een klas te verwijderen.
|
||||
</p>
|
||||
<div id="koppelingContent"><div class="empty">Laden...</div></div>
|
||||
</div>
|
||||
@@ -314,6 +320,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// Export knoppen
|
||||
document.getElementById('btnExportCSV').addEventListener('click', exportCSV);
|
||||
document.getElementById('btnNieuweKlas').addEventListener('click', openNieuweKlasDialog);
|
||||
document.getElementById('btnKoppelingAnnuleer').addEventListener('click', () => {
|
||||
document.getElementById('koppelingModal').style.display = 'none';
|
||||
});
|
||||
@@ -574,6 +581,9 @@ function applyFilters() {
|
||||
if (leeftFilter.length > 0 && !leeftFilter.some(l=>goal.leeftijden.includes(l))) return;
|
||||
if (sectieFilter !== 'all' && goal.sectie !== sectieFilter) return;
|
||||
const statussen = klassen.map(k => (overviewData.assessments_by_class[k.id]?.[vakId]?.[goal.id])||'');
|
||||
if (statusFilter==='groen' && !statussen.some(s=>s==='groen')) return;
|
||||
if (statusFilter==='oranje' && !statussen.some(s=>s==='oranje')) return;
|
||||
if (statusFilter==='roze' && !statussen.some(s=>s==='roze')) return;
|
||||
if (statusFilter==='consensus' && !statussen.every(s=>s==='groen')) return;
|
||||
if (statusFilter==='verschil') {
|
||||
const filled = statussen.filter(Boolean);
|
||||
@@ -739,17 +749,33 @@ async function renderKoppelingTab() {
|
||||
const teacherUsers = allUsers.filter(u => u.role === 'teacher' || u.role === 'director');
|
||||
el.innerHTML = '<div class="vak-grid">' + klassen.map(k => {
|
||||
const teachers = (k.teachers||[]).map(t => t.full_name).join(', ') || '<em style="color:var(--gray-400)">Geen leerkrachten</em>';
|
||||
return `<div class="vak-card" style="cursor:pointer;" data-action="openKoppeling" data-id="${k.id}" data-name="${k.name.replace(/"/g,'"')}" data-teachers="${JSON.stringify((k.teachers||[]).map(t=>t.id)).replace(/"/g,'"')}">
|
||||
<div class="vak-card-header">
|
||||
return `<div class="vak-card" style="position:relative;">
|
||||
<div class="vak-card-header" style="cursor:pointer;" data-action="openKoppeling" data-id="${k.id}" data-name="${k.name.replace(/"/g,'"')}" data-teachers="${JSON.stringify((k.teachers||[]).map(t=>t.id)).replace(/"/g,'"')}">
|
||||
<h3>🏫 ${k.name}</h3>
|
||||
<span style="font-size:.75rem;background:var(--primary);color:white;padding:.2rem .5rem;border-radius:4px;">Wijzigen</span>
|
||||
</div>
|
||||
<div style="font-size:.82rem;color:var(--gray-600);">${teachers}</div>
|
||||
<div style="font-size:.82rem;color:var(--gray-600);margin-top:.4rem;">${teachers}</div>
|
||||
<button data-action="deleteKlas" data-id="${k.id}" data-name="${k.name.replace(/"/g,'"')}"
|
||||
style="position:absolute;top:.5rem;right:.5rem;background:none;border:none;cursor:pointer;font-size:1rem;color:var(--gray-400);line-height:1;"
|
||||
title="Klas verwijderen">🗑</button>
|
||||
</div>`;
|
||||
}).join('') + '</div>';
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
// Verwijder klas
|
||||
const delBtn = e.target.closest('[data-action="deleteKlas"]');
|
||||
if (delBtn) {
|
||||
const id = parseInt(delBtn.dataset.id);
|
||||
const name = delBtn.dataset.name;
|
||||
if (!confirm(`Klas "${name}" verwijderen? Alle beoordelingen voor deze klas gaan verloren.`)) return;
|
||||
fetch(`/api/classes/${id}`, {method: 'DELETE'})
|
||||
.then(r => { if (r.ok) { showNotification(`Klas "${name}" verwijderd`, 'success'); loadOverview(); }
|
||||
else showNotification('Verwijderen mislukt', 'error'); });
|
||||
return;
|
||||
}
|
||||
|
||||
// Wijzig leerkrachten
|
||||
const card = e.target.closest('[data-action="openKoppeling"]');
|
||||
if (!card) return;
|
||||
activeKlasKoppeling = parseInt(card.dataset.id);
|
||||
@@ -772,6 +798,20 @@ document.addEventListener('click', function(e) {
|
||||
document.getElementById('koppelingModal').style.display = 'flex';
|
||||
});
|
||||
|
||||
async function openNieuweKlasDialog() {
|
||||
const name = prompt('Naam van de nieuwe klas:');
|
||||
if (!name || !name.trim()) return;
|
||||
const res = await fetch('/api/classes', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({name: name.trim()})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) { showNotification(data.error || 'Aanmaken mislukt', 'error'); return; }
|
||||
showNotification(`Klas "${data.class.name}" aangemaakt`, 'success');
|
||||
await loadOverview();
|
||||
}
|
||||
|
||||
async function saveKoppeling() {
|
||||
if (!activeKlasKoppeling) return;
|
||||
const checked = [...document.querySelectorAll('#koppelingCheckboxes input:checked')].map(i => parseInt(i.value));
|
||||
|
||||
Reference in New Issue
Block a user