atlas-academy/static/bisl.html
Atlas Developer 03829a38b2 feat: Atlas Academy — Odoo eLearning platform, full fusion
9-course Dutch e-learning platform fused onto atlasacademy.nl via Caddy
reverse proxy. Odoo 19 Community as course engine (website_slides), static
HTML for marketing front. Single Odoo account system.

- static/: 8 marketing pages (index, pricing, coaching, leerpad, over, shop, bisl, esf)
- backend/odoo_relay.py: lead relay Flask service (POST /academy-lead → Odoo CRM)
- caddy/academy.caddyfile: full Caddy config with Odoo proxy + auth rewrites
- docs/: ARCHITECTURE, USERFLOW, COURSES, DEPLOYMENT, SECURITY, ODOO

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 00:48:45 +02:00

1191 lines
53 KiB
HTML

<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="BiSL Foundation — Atlas Academy — Atlas Academy">
<title>BiSL Foundation — Atlas Academy</title>
<style>
:root {
--blue: #3B82F6;
--blue-dark: #2563EB;
--blue-light: #DBEAFE;
--green: #10B981;
--green-light: #D1FAE5;
--yellow: #F59E0B;
--yellow-light: #FEF3C7;
--gray-50: #F9FAFB;
--gray-100: #F3F4F6;
--gray-200: #E5E7EB;
--gray-300: #D1D5DB;
--gray-500: #6B7280;
--gray-700: #374151;
--gray-900: #111827;
--sidebar-width: 260px;
--radius: 8px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--gray-50);
color: var(--gray-900);
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* ── TOP NAV ── */
.topnav {
background: #1E293B;
color: #CBD5E1;
display: flex;
align-items: center;
gap: 12px;
padding: 0 20px;
height: 48px;
flex-shrink: 0;
font-size: 0.85rem;
border-bottom: 1px solid #334155;
}
.topnav a { color: #94A3B8; text-decoration: none; }
.topnav a:hover { color: #fff; }
.topnav-sep { color: #475569; }
.topnav-current { color: #E2E8F0; font-weight: 500; }
/* ── LAYOUT ── */
.layout {
display: flex;
flex: 1;
min-height: 0;
}
/* ── SIDEBAR ── */
.sidebar {
width: var(--sidebar-width);
min-width: var(--sidebar-width);
background: #fff;
border-right: 1px solid var(--gray-200);
display: flex;
flex-direction: column;
height: calc(100vh - 48px);
position: sticky;
top: 48px;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--gray-200) transparent;
}
.sidebar::-webkit-scrollbar { width: 4px; }
.sidebar::-webkit-scrollbar-track { background: transparent; }
.sidebar::-webkit-scrollbar-thumb { background: var(--gray-300); border-radius: 2px; }
.sidebar-header {
padding: 18px 16px 12px;
border-bottom: 1px solid var(--gray-100);
flex-shrink: 0;
}
.sidebar-title {
font-size: 0.95rem;
font-weight: 700;
color: var(--gray-900);
line-height: 1.3;
margin-bottom: 10px;
}
.progress-wrap { margin-top: 2px; }
.progress-label {
display: flex;
justify-content: space-between;
font-size: 0.72rem;
color: var(--gray-500);
margin-bottom: 4px;
}
.progress-bar {
background: var(--gray-200);
border-radius: 99px;
height: 6px;
overflow: hidden;
}
.progress-fill {
background: var(--blue);
height: 100%;
border-radius: 99px;
transition: width 0.4s ease;
}
.sidebar-nav { flex: 1; padding: 8px 0; }
.cluster-label {
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--gray-500);
padding: 10px 16px 4px;
}
.lesson-item {
display: flex;
align-items: center;
gap: 8px;
padding: 7px 16px;
cursor: pointer;
font-size: 0.82rem;
color: var(--gray-700);
line-height: 1.3;
border-left: 3px solid transparent;
transition: background 0.12s, color 0.12s;
user-select: none;
}
.lesson-item:hover { background: var(--gray-50); color: var(--blue-dark); }
.lesson-item.active {
background: var(--blue-light);
color: var(--blue-dark);
font-weight: 600;
border-left-color: var(--blue);
}
.lesson-num {
font-size: 0.7rem;
font-weight: 700;
color: var(--gray-500);
min-width: 18px;
text-align: right;
flex-shrink: 0;
}
.lesson-item.active .lesson-num { color: var(--blue); }
.lesson-check {
margin-left: auto;
flex-shrink: 0;
font-size: 0.75rem;
color: var(--green);
display: none;
}
.lesson-item.learned .lesson-check { display: block; }
.sidebar-footer {
border-top: 1px solid var(--gray-100);
padding: 10px 12px;
flex-shrink: 0;
}
.sidebar-footer a {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.78rem;
color: var(--gray-500);
text-decoration: none;
padding: 6px 4px;
border-radius: 6px;
transition: color 0.12s, background 0.12s;
}
.sidebar-footer a:hover { color: var(--blue-dark); background: var(--gray-50); }
/* ── MAIN ── */
.main {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.course-header {
background: linear-gradient(135deg, #1E293B 0%, #1e3a5f 100%);
color: #fff;
padding: 28px 36px 24px;
display: flex;
align-items: flex-start;
gap: 18px;
flex-shrink: 0;
}
.course-header-icon { font-size: 2.4rem; line-height: 1; flex-shrink: 0; margin-top: 2px; }
.course-header-body { flex: 1; }
.course-header-badges { display: flex; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
.badge-gratis {
background: #10B981;
color: #fff;
font-size: 0.72rem;
font-weight: 700;
padding: 2px 10px;
border-radius: 99px;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.badge-exin {
background: rgba(255,255,255,0.15);
color: #CBD5E1;
font-size: 0.72rem;
font-weight: 600;
padding: 2px 10px;
border-radius: 99px;
}
.course-header h1 {
font-size: 1.6rem;
font-weight: 800;
line-height: 1.2;
margin-bottom: 6px;
}
.course-meta {
font-size: 0.82rem;
color: #94A3B8;
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.course-meta span::before { content: '·'; margin-right: 6px; }
.course-meta span:first-child::before { content: ''; margin-right: 0; }
/* ── CONTENT AREA ── */
.content-area {
flex: 1;
padding: 28px 36px;
max-width: 860px;
}
/* ── OVERVIEW ── */
.overview-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 28px;
}
.overview-card {
background: #fff;
border: 1px solid var(--gray-200);
border-radius: var(--radius);
padding: 20px;
}
.overview-card h3 {
font-size: 0.9rem;
font-weight: 700;
color: var(--gray-900);
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 6px;
}
.overview-card ul {
list-style: none;
display: flex;
flex-direction: column;
gap: 7px;
}
.overview-card li {
font-size: 0.83rem;
color: var(--gray-700);
display: flex;
align-items: flex-start;
gap: 8px;
line-height: 1.4;
}
.overview-card li::before {
content: '✓';
color: var(--green);
font-weight: 700;
font-size: 0.8rem;
flex-shrink: 0;
margin-top: 1px;
}
.start-cta {
background: var(--blue);
color: #fff;
border: none;
padding: 13px 28px;
border-radius: var(--radius);
font-size: 0.95rem;
font-weight: 700;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
transition: background 0.15s;
}
.start-cta:hover { background: var(--blue-dark); }
/* ── LESSON VIEW ── */
.lesson-view { display: none; }
.lesson-view.active { display: block; }
.lesson-cluster-tag {
display: inline-block;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 3px 10px;
border-radius: 99px;
margin-bottom: 10px;
}
.cl-gb { background: #DBEAFE; color: #1D4ED8; }
.cl-fb { background: #D1FAE5; color: #065F46; }
.cl-vb { background: #FEF3C7; color: #92400E; }
.cl-st { background: #EDE9FE; color: #5B21B6; }
.cl-rg { background: #FCE7F3; color: #9D174D; }
.cl-sn { background: #F1F5F9; color: #475569; }
.lesson-title {
font-size: 1.5rem;
font-weight: 800;
color: var(--gray-900);
margin-bottom: 20px;
line-height: 1.25;
}
.lesson-body {
background: #fff;
border: 1px solid var(--gray-200);
border-radius: var(--radius);
padding: 24px;
font-size: 0.9rem;
line-height: 1.7;
color: var(--gray-700);
margin-bottom: 20px;
}
.terms-box {
background: var(--gray-50);
border: 1px solid var(--gray-200);
border-radius: var(--radius);
padding: 20px;
margin-bottom: 20px;
}
.terms-box h4 {
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--gray-500);
margin-bottom: 12px;
}
.term-row {
display: flex;
gap: 12px;
padding: 8px 0;
border-bottom: 1px solid var(--gray-200);
font-size: 0.84rem;
line-height: 1.4;
}
.term-row:last-child { border-bottom: none; }
.term-name { font-weight: 700; color: var(--gray-900); min-width: 180px; flex-shrink: 0; }
.term-def { color: var(--gray-700); }
.tip-box {
background: var(--yellow-light);
border: 1px solid #FDE68A;
border-left: 4px solid var(--yellow);
border-radius: var(--radius);
padding: 14px 18px;
font-size: 0.86rem;
color: #78350F;
margin-bottom: 24px;
display: flex;
gap: 10px;
align-items: flex-start;
}
.tip-icon { flex-shrink: 0; font-size: 1rem; margin-top: 1px; }
/* ── SESSIENOTITIES ── */
.notes-view { display: none; }
.notes-view.active { display: block; }
.day-tabs {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
.day-tab {
padding: 7px 18px;
border-radius: 99px;
font-size: 0.83rem;
font-weight: 600;
cursor: pointer;
border: 2px solid var(--gray-200);
background: #fff;
color: var(--gray-500);
transition: all 0.15s;
}
.day-tab.active {
background: var(--blue);
border-color: var(--blue);
color: #fff;
}
.note-card {
background: #fff;
border: 1px solid var(--gray-200);
border-radius: var(--radius);
padding: 18px;
margin-bottom: 12px;
}
.note-topic {
font-size: 0.92rem;
font-weight: 700;
color: var(--gray-900);
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.note-topic::before { content: '📌'; font-size: 0.85rem; }
.note-punten {
list-style: none;
margin-bottom: 10px;
display: flex;
flex-direction: column;
gap: 5px;
}
.note-punten li {
font-size: 0.83rem;
color: var(--gray-700);
padding-left: 14px;
position: relative;
line-height: 1.4;
}
.note-punten li::before {
content: '•';
position: absolute;
left: 0;
color: var(--blue);
}
.note-begrippen {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 8px;
}
.note-begrip {
font-size: 0.8rem;
background: var(--gray-50);
border: 1px solid var(--gray-200);
border-radius: 4px;
padding: 4px 10px;
color: var(--gray-700);
}
.note-begrip b { color: var(--gray-900); }
.note-tip {
font-size: 0.79rem;
color: #78350F;
background: var(--yellow-light);
border-radius: 4px;
padding: 6px 10px;
margin-top: 6px;
}
/* ── LESSON NAVIGATION ── */
.lesson-nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 0 0;
border-top: 1px solid var(--gray-200);
margin-top: 8px;
}
.nav-btn {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 9px 18px;
border: 1px solid var(--gray-200);
border-radius: var(--radius);
background: #fff;
font-size: 0.83rem;
font-weight: 600;
color: var(--gray-700);
cursor: pointer;
text-decoration: none;
transition: all 0.15s;
}
.nav-btn:hover { background: var(--gray-50); color: var(--blue-dark); border-color: var(--blue); }
.nav-btn:disabled, .nav-btn.hidden { opacity: 0; pointer-events: none; }
.nav-btn.primary {
background: var(--blue);
color: #fff;
border-color: var(--blue);
}
.nav-btn.primary:hover { background: var(--blue-dark); border-color: var(--blue-dark); }
.learned-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
border: 2px solid var(--gray-200);
border-radius: var(--radius);
background: #fff;
font-size: 0.82rem;
font-weight: 600;
color: var(--gray-700);
cursor: pointer;
transition: all 0.15s;
}
.learned-btn:hover { border-color: var(--green); color: var(--green); }
.learned-btn.is-learned { border-color: var(--green); color: var(--green); background: var(--green-light); }
/* ── EXAM CTA ── */
.exam-cta {
background: linear-gradient(135deg, #1E293B, #1e3a5f);
border-radius: var(--radius);
padding: 24px 28px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
margin-top: 32px;
flex-wrap: wrap;
}
.exam-cta-text h3 {
color: #fff;
font-size: 1rem;
font-weight: 700;
margin-bottom: 4px;
}
.exam-cta-text p { color: #94A3B8; font-size: 0.83rem; }
.exam-cta-link {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(--blue);
color: #fff;
text-decoration: none;
padding: 11px 22px;
border-radius: var(--radius);
font-size: 0.88rem;
font-weight: 700;
transition: background 0.15s;
white-space: nowrap;
flex-shrink: 0;
}
.exam-cta-link:hover { background: var(--blue-dark); }
/* ── MOBILE ── */
@media (max-width: 720px) {
.layout { flex-direction: column; }
.sidebar {
width: 100%;
min-width: unset;
height: auto;
position: static;
border-right: none;
border-bottom: 1px solid var(--gray-200);
max-height: 240px;
}
.course-header { padding: 20px 18px 16px; }
.course-header h1 { font-size: 1.25rem; }
.content-area { padding: 20px 18px; }
.overview-grid { grid-template-columns: 1fr; }
.term-name { min-width: 130px; }
}
</style>
<!-- GA4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-JBWZWZMKBC"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','G-JBWZWZMKBC');</script>
<meta name="robots" content="index, follow">
</head>
<body>
<script>
/* ── Atlas Academy auth gate ── */
(function(){
var tok=localStorage.getItem('aa_token');
if(!tok){window.location.replace('/login.html?next='+encodeURIComponent(window.location.pathname));return;}
try{
var p=tok.split('.');if(p.length!==3)throw 0;
var pay=JSON.parse(atob((p[1]+'==').replace(/-/g,'+').replace(/_/g,'/')));
if(!pay.exp||Date.now()/1000>pay.exp)throw 0;
window.ATLAS_USER={name:pay.name,email:pay.sub};
}catch(e){localStorage.removeItem('aa_token');window.location.replace('/login.html?next='+encodeURIComponent(window.location.pathname));}
})();
</script>
<!-- TOP NAV -->
<nav class="topnav">
<a href="../cursussen.html">Atlas Academy</a>
<span class="topnav-sep">/</span>
<a href="../cursussen.html">Cursussen</a>
<span class="topnav-sep">/</span>
<span class="topnav-current">BiSL Foundation</span>
</nav>
<div class="layout">
<!-- SIDEBAR -->
<aside class="sidebar" id="sidebar">
<div class="sidebar-header">
<div class="sidebar-title">📚 BiSL Foundation</div>
<div class="progress-wrap">
<div class="progress-label">
<span>Voortgang</span>
<span id="progress-text">0 / 17</span>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progress-fill" style="width:0%"></div>
</div>
</div>
</div>
<nav class="sidebar-nav" id="lesson-nav">
<!-- Rendered by JS -->
</nav>
<div class="sidebar-footer">
<a href="../cursussen.html">&#8592; Alle cursussen</a>
</div>
</aside>
<!-- MAIN -->
<div class="main">
<!-- COURSE HEADER -->
<div class="course-header">
<div class="course-header-icon">📚</div>
<div class="course-header-body">
<div class="course-header-badges">
<span class="badge-gratis">GRATIS</span>
<span class="badge-exin">EXIN gecertificeerd</span>
</div>
<h1>BiSL Foundation</h1>
<div class="course-meta">
<span>17 lessen</span>
<span>97 oefenvragen</span>
<span>Sessienotities dag 2+3</span>
<span>EXIN gecertificeerd</span>
</div>
</div>
</div>
<!-- CONTENT AREA -->
<div class="content-area">
<!-- OVERVIEW (default) -->
<div id="view-overview">
<div class="overview-grid">
<div class="overview-card">
<h3>✅ Wat je leert</h3>
<ul>
<li>Het BiSL Framework en alle procesclusters</li>
<li>Gebruiksbeheer: ondersteuning, communicatie, IT-aansturing</li>
<li>Functionaliteitenbeheer: behoeftemanagement t/m transitie</li>
<li>Verbindende processen: wijzigingenbeheer & leveranciersmanagement</li>
<li>Sturende en richtinggevende processen</li>
<li>Examentips bij elke les — herkenbaar voor EXIN-vragen</li>
</ul>
</div>
<div class="overview-card">
<h3>🎯 Wie is dit voor</h3>
<ul>
<li>Kandidaten die het EXIN BiSL Foundation examen afleggen</li>
<li>Functioneel beheerders die hun kennis willen structureren</li>
<li>IT-professionals die de vraagzijde willen begrijpen</li>
<li>Deelnemers aan een BiSL-training (incl. sessienotities)</li>
<li>Zelfstudenten zonder trainingservaring</li>
</ul>
</div>
</div>
<button class="start-cta" onclick="loadLesson(0)">&#9654;&#xFE0E; Aan de slag — Start les 1</button>
</div>
<!-- LESSON VIEW -->
<div class="lesson-view" id="view-lesson">
<span class="lesson-cluster-tag" id="lesson-cluster-tag"></span>
<div class="lesson-title" id="lesson-title"></div>
<div class="lesson-body" id="lesson-body"></div>
<div class="terms-box" id="terms-box" style="display:none">
<h4>Begrippen</h4>
<div id="terms-list"></div>
</div>
<div class="tip-box" id="tip-box" style="display:none">
<span class="tip-icon">💡</span>
<span id="tip-text"></span>
</div>
<div class="lesson-nav">
<button class="nav-btn" id="btn-prev" onclick="navLesson(-1)">&#8592; Vorige les</button>
<button class="learned-btn" id="btn-learned" onclick="toggleLearned()">Markeer als geleerd ✓</button>
<button class="nav-btn primary" id="btn-next" onclick="navLesson(1)">Volgende les &#8594;</button>
</div>
<div class="exam-cta">
<div class="exam-cta-text">
<h3>Klaar voor het examen?</h3>
<p>97 oefenvragen — direct feedback per vraag — EXIN-stijl</p>
</div>
<a class="exam-cta-link" href="/bisl.html">&#127919; Ga naar de examentrainer &#8594;</a>
</div>
</div>
<!-- SESSIENOTITIES VIEW -->
<div class="notes-view" id="view-notes">
<div class="lesson-title" id="notes-title"></div>
<div class="day-tabs">
<div class="day-tab active" id="tab-dag2" onclick="showNoteDay('dag2')">Dag 2</div>
<div class="day-tab" id="tab-dag3" onclick="showNoteDay('dag3')">Dag 3</div>
</div>
<div id="notes-content"></div>
<div class="lesson-nav">
<button class="nav-btn" onclick="goOverview()">&#8592; Terug naar overzicht</button>
<span></span>
<a class="nav-btn primary" href="/bisl.html">&#127919; Examentrainer</a>
</div>
</div>
</div><!-- /content-area -->
</div><!-- /main -->
</div><!-- /layout -->
<script>
// ══════════════════════════════════════════════════════════════════════════════
// DATA — LESSONS
// ══════════════════════════════════════════════════════════════════════════════
const LESSONS = [
{
id:'framework', cluster:'Overzicht', clusterClass:'cl-gb',
title:'BiSL Framework',
body:`<b>BiSL</b> (Business Information Services Library) is een raamwerk voor <b>functioneel beheer</b> en <b>business informatiemanagement</b>. Het kijkt vanuit de <b>gebruikersorganisatie</b> — niet vanuit IT. De functioneel beheerder zorgt ervoor dat de informatievoorziening aansluit op wat de organisatie nodig heeft.<br><br>
BiSL kent <b>drie uitvoerende procesclusters</b>: <b>Gebruiksbeheer</b> (dagelijks gebruik), <b>Functionaliteitenbeheer</b> (verbetering &amp; wijziging) en <b>Verbindende processen</b> (koppeling tussen de twee). Daarboven zitten de <b>Sturende processen</b> (sturing &amp; beheersing) en de <b>Richtinggevende processen</b> (strategie).`,
terms:[
{t:'Functioneel beheer', d:'Beheer van informatievoorziening vanuit de gebruikersorganisatie'},
{t:'Informatievoorziening (IV)', d:'Alle informatie die een organisatie nodig heeft voor haar processen'},
{t:'Vraagzijde vs aanbodzijde', d:'BiSL = vraagzijde (business); ITIL = aanbodzijde (IT-leverancier)'},
],
tip:'BiSL staat altijd aan de kant van de gebruiker/business, nooit aan de kant van IT. Dit onderscheid komt vaak terug in examen.'
},
{
id:'gebruikersondersteuning', cluster:'Gebruiksbeheer', clusterClass:'cl-gb',
title:'Gebruikersondersteuning',
body:`Gebruikersondersteuning behandelt <b>vragen, meldingen en incidenten</b> van gebruikers over de informatievoorziening. Denk aan: "Ik kan niet inloggen", "het systeem doet iets raars", "hoe werkt functie X".<br><br>
De functioneel beheerder fungeert hier als <b>eerste aanspreekpunt</b>. Hij lost op wat hij kan, en escaleert naar IT wat technisch is. Het proces houdt ook de <b>call-administratie</b> bij: welke vragen komen er, hoe snel worden ze opgelost?`,
terms:[
{t:'Call', d:'Een melding of vraag van een gebruiker'},
{t:'Helpdesk / servicedesk', d:'De plek waar calls binnenkomen en worden geregistreerd'},
{t:'Escalatie', d:'Doorsturen van een call naar IT als het technisch is'},
],
tip:'Als in het examen iemand belt met een probleem of vraag → Gebruikersondersteuning.'
},
{
id:'beheer-bedrijfsinformatie', cluster:'Gebruiksbeheer', clusterClass:'cl-gb',
title:'Beheer bedrijfsinformatie',
body:`Dit proces zorgt voor de <b>kwaliteit van de gegevens</b> in de systemen. Stamgegevens — relatief stabiele, veelgebruikte basisgegevens — worden hier beheerd. Denk aan: klantgegevens, productcatalogi, personeelsgegevens.<br><br>
De functioneel beheerder bewaakt dat de gegevens <b>juist, volledig en actueel</b> zijn. Dit gaat niet over de technische opslag (dat is IT), maar over de <b>inhoudelijke kwaliteit</b> vanuit de business.`,
terms:[
{t:'Stamgegeven', d:'Relatief stabiel, veelgebruikt basisdatum (bijv. klant- of productgegevens)'},
{t:'Gegevenskwaliteit', d:'Juist, volledig, actueel en consistent zijn van data'},
],
tip:'Vragen over datakwaliteit, klantgegevens bijhouden → Beheer bedrijfsinformatie.'
},
{
id:'gebruikerscommunicatie', cluster:'Gebruiksbeheer', clusterClass:'cl-gb',
title:'Gebruikerscommunicatie',
body:`Dit proces informeert de gebruikersorganisatie over de <b>stand van zaken rondom de informatievoorziening</b>. Denk aan: geplande onderhoudsstops, nieuwe functionaliteit, wijzigingen in procedures.<br><br>
Het gaat altijd van de functioneel beheerder <b>naar</b> de gebruikers — niet andersom. Communicatie van gebruikers <i>naar</i> de functioneel beheerder is Gebruikersondersteuning of Behoeftemanagement.`,
terms:[
{t:'Communicatieplan', d:'Plan voor hoe en wanneer gebruikers geïnformeerd worden'},
{t:'Releasebericht', d:'Aankondiging van nieuwe functionaliteit of wijzigingen'},
],
tip:'Richting is alles: functioneel beheerder → gebruikers = Gebruikerscommunicatie.'
},
{
id:'operationele-it', cluster:'Gebruiksbeheer', clusterClass:'cl-gb',
title:'Operationele IT-aansturing',
body:`Dit proces regelt de dagelijkse <b>aansturing van de IT-leverancier</b>. De functioneel beheerder bewaakt of IT de afgesproken diensten levert zoals vastgelegd in de <b>SLA</b> (Service Level Agreement).<br><br>
Als de systeemprestaties achterblijven, is het dit proces dat IT aanspreekt. Het gaat dus om de <b>operationele uitvoering</b> van contractuele afspraken, niet om het afsluiten van contracten (dat is Leveranciersmanagement).`,
terms:[
{t:'SLA (Service Level Agreement)', d:'Contract over prestatienormen: beschikbaarheid, responsetijd, etc.'},
{t:'KPI', d:'Meetpunt om te beoordelen of IT de SLA naleeft'},
],
tip:'SLA monitoring, dagelijkse IT-aansturing → Operationele IT-aansturing. Contract afsluiten → Leveranciersmanagement.'
},
{
id:'ketenafstemming', cluster:'Gebruiksbeheer', clusterClass:'cl-gb',
title:'Operationele ketenafstemming',
body:`Veel organisaties werken in <b>ketens</b>: hun systemen zijn gekoppeld aan die van partners, klanten of leveranciers. Operationele ketenafstemming zorgt voor de <b>dagelijkse afstemming met deze ketenpartners</b>.<br><br>
Denk aan: afstemming over uitwisselformaten, verwerkingstijden, gecombineerde procedures. Dit is operationeel — de strategische kant zit in de richtinggevende processen.`,
terms:[
{t:'Ketenpartner', d:'Externe partij waarmee de informatievoorziening gekoppeld is'},
{t:'Ketenafstemming', d:'Operationele coördinatie over gezamenlijke informatieprocessen'},
],
tip:'Externe partijen, gekoppelde systemen, dagelijkse afstemming → Operationele ketenafstemming.'
},
{
id:'behoeftemanagement', cluster:'Functionaliteitenbeheer', clusterClass:'cl-fb',
title:'Behoeftemanagement',
body:`Behoeftemanagement is het <b>begin van de verbeteringscyclus</b>. Hier worden wensen en behoeften van gebruikers <b>gesignaleerd, verzameld en geprioriteerd</b>. De functioneel beheerder filtert wat realistisch is en stelt prioriteiten vast samen met de business.<br><br>
De output is een <b>geordend overzicht van wensen</b> dat als input dient voor Specificeren. Niet alles wat gebruikers willen gaat er meteen in — prioritering is essentieel.`,
terms:[
{t:'Wens / behoefte', d:'Wat een gebruiker anders of beter wil in de informatievoorziening'},
{t:'Prioritering', d:'Bepalen welke wensen het eerst worden uitgewerkt'},
{t:'Signalering', d:'Pro-actief zoeken naar wat gebruikers nodig hebben'},
],
tip:'Eerste stap in de cyclus. Wensen ophalen en prioriteren → Behoeftemanagement.'
},
{
id:'specificeren', cluster:'Functionaliteitenbeheer', clusterClass:'cl-fb',
title:'Specificeren',
body:`Na behoeftemanagement worden de geprioriteerde wensen uitgewerkt tot <b>concrete, meetbare eisen</b>. De output is een <b>Programma van Eisen (PvE)</b> of een functioneel ontwerp.<br><br>
Dit document beschrijft <i>wat</i> het systeem moet kunnen — niet <i>hoe</i> het technisch gebouwd wordt. Het PvE gaat naar de IT-leverancier als formele opdracht. De functioneel beheerder zorgt dat de eisen duidelijk en compleet zijn.`,
terms:[
{t:'Programma van Eisen (PvE)', d:'Formeel document met functionele eisen voor de IT-leverancier'},
{t:'Functioneel ontwerp', d:'Beschrijving van gewenste functionaliteit in business-termen'},
{t:'Pakketkeuze', d:'Kiezen tussen software-oplossingen op basis van het PvE'},
],
tip:'PvE, aanbesteding, selectie van software → Specificeren.'
},
{
id:'toetsen-testen', cluster:'Functionaliteitenbeheer', clusterClass:'cl-fb',
title:'Toetsen &amp; testen',
body:`Toetsen &amp; testen beoordeelt of de opgeleverde functionaliteit <b>voldoet aan de functionele eisen</b> van de gebruikersorganisatie. Dit is <b>geen technische test</b> — dat doet IT. De functioneel beheerder organiseert de <b>gebruikersacceptatietest</b> (UAT).<br><br>
Bij een positief testresultaat geeft de functioneel beheerder een <b>go</b> voor implementatie. Bij problemen gaat het terug naar de leverancier. De functioneel beheerder is de poortwachter vóór productie.`,
terms:[
{t:'Gebruikersacceptatietest (UAT)', d:'Test waarbij gebruikers beoordelen of de software voldoet aan hun eisen'},
{t:'Go / no-go', d:'Beslissing of software door kan naar productie'},
{t:'Testscenario', d:'Situatie die getest wordt om eisen te verifiëren'},
],
tip:'UAT, acceptatietest, go/no-go beslissing → Toetsen &amp; testen.'
},
{
id:'transitie', cluster:'Functionaliteitenbeheer', clusterClass:'cl-fb',
title:'Transitie',
body:`Transitie brengt <b>goedgekeurde nieuwe functionaliteit naar de productieomgeving</b>. Denk aan: inrichten van de nieuwe versie, opleiden van gebruikers, aanpassen van procedures en handleidingen, en begeleiden van de omschakeling.<br><br>
Na de go van Toetsen &amp; testen zorgt Transitie dat alles klaar is voor de gebruikers. Het gaat om de <b>implementatie in de breedte</b> — niet alleen technisch beschikbaar stellen (dat doet IT), maar ook organisatorisch gereedmaken.`,
terms:[
{t:'Productie-situatie', d:'De live omgeving die gebruikers dagelijks gebruiken'},
{t:'Vrijgave', d:'Officieel beschikbaar stellen van nieuwe functionaliteit'},
{t:'Implementatieplan', d:'Plan voor de overgang naar de nieuwe situatie'},
],
tip:'Ingebruikname, training gebruikers, livegang → Transitie.'
},
{
id:'niet-geautomatiseerd', cluster:'Functionaliteitenbeheer', clusterClass:'cl-fb',
title:'Vormgeven niet-geautomatiseerde IV',
body:`Niet alle informatievoorziening loopt via computers. Dit proces richt zich op <b>formulieren, procedures, werkinstructies en handmatige processen</b> die onderdeel zijn van de informatievoorziening maar niet geautomatiseerd zijn.<br><br>
De functioneel beheerder zorgt ook hier voor kwaliteit en aansluiting op de organisatiebehoeften. Dit wordt vaak vergeten, maar het EXIN-examen vraagt er zeker naar.`,
terms:[
{t:'Niet-geautomatiseerde IV', d:'Papieren formulieren, handmatige registraties, mondelinge procedures'},
{t:'Werkinstructie', d:'Beschrijving van hoe een handmatig proces uitgevoerd moet worden'},
],
tip:'Formulieren, handmatige procedures, papieren processen → Niet-geautomatiseerde IV.'
},
{
id:'wijzigingenbeheer', cluster:'Verbindende processen', clusterClass:'cl-vb',
title:'Wijzigingenbeheer',
body:`Wijzigingenbeheer <b>coördineert alle wijzigingen</b> aan de informatievoorziening. Het staat tussen Gebruiksbeheer en Functionaliteitenbeheer in, en bewaakt dat wijzigingen gecontroleerd en gepland verlopen.<br><br>
Het beheert de <b>implementatiekalender</b>: wanneer wordt wat doorgevoerd? Wijzigingenbeheer stemt af met IT, maar kijkt altijd vanuit de gebruikersorganisatie — het is niet hetzelfde als ITIL change management.`,
terms:[
{t:'Implementatiekalender', d:'Planning van wanneer wijzigingen doorgevoerd worden'},
{t:'RFC (Request for Change)', d:'Formeel verzoek voor een wijziging'},
{t:'Wijzigingsoverleg', d:'Overleg met IT en business over planning van wijzigingen'},
],
tip:'Implementatiekalender, coördinatie van wijzigingen, afstemming IT en business → Wijzigingenbeheer.'
},
{
id:'leveranciersmanagement', cluster:'Verbindende processen', clusterClass:'cl-vb',
title:'Leveranciersmanagement',
body:`Leveranciersmanagement beheert de <b>contractuele relatie met IT-leveranciers</b>. Het sluit contracten af, onderhandelt over voorwaarden en beheert het <b>DAP</b> (Dossier Afspraken en Procedures).<br><br>
Het verschil met Operationele IT-aansturing: Leveranciersmanagement gaat over de <b>strategisch-tactische contractkant</b>, Operationele IT-aansturing over de <b>dagelijkse uitvoering</b>.`,
terms:[
{t:'DAP (Dossier Afspraken en Procedures)', d:'Document met alle afspraken en procedures met de leverancier'},
{t:'Contractmanagement', d:'Beheren en bewaken van contracten met IT-leveranciers'},
{t:'Leveranciersoverleg', d:'Periodiek overleg met de IT-leverancier over de samenwerking'},
],
tip:'DAP, contracten afsluiten, onderhandeling leverancier → Leveranciersmanagement.'
},
{
id:'sturend', cluster:'Sturende processen', clusterClass:'cl-st',
title:'Sturende processen',
body:`De sturende processen sturen en bewaken de uitvoerende processen. Ze zorgen voor <b>planning, kwaliteit, security en continuïteit</b> van het functioneel beheer als geheel.<br><br>
De vijf sturende processen zijn: <b>Planning &amp; control</b> (jaarplan, budget), <b>Kwaliteitsmanagement</b> (kwaliteit van processen), <b>Securitymanagement</b> (autorisaties vanuit business), <b>Beschikbaarheid &amp; capaciteitsbeheer</b> en <b>Info-portfoliomanagement</b> (portfolio van IV).`,
terms:[
{t:'Jaarplan', d:'Jaarlijkse planning van activiteiten en budget voor functioneel beheer'},
{t:'Autorisatiebeheer', d:'Beheer van wie toegang heeft tot welke informatie (vanuit business)'},
{t:'IV-portfolio', d:'Overzicht van alle informatiesystemen en -voorzieningen'},
],
tip:'Sturende processen zijn tactisch/besturend. Ze zijn niet operationeel — ze regisseren, ze doen niet zelf.'
},
{
id:'richtinggevend', cluster:'Richtinggevende processen', clusterClass:'cl-rg',
title:'Richtinggevende processen',
body:`De richtinggevende processen bepalen de <b>langetermijnkoers</b> van de informatievoorziening. Ze werken op <b>strategisch niveau</b> en geven richting aan alle andere processen.<br><br>
De drie richtinggevende processen zijn: <b>Opstellen informatiestrategie</b> (wat willen we met IV?), <b>IV-organisatiestrategie</b> (hoe organiseren we de IV-functie?) en <b>Informatie-coördinatie</b> (afstemming tussen IV-strategieën van verschillende onderdelen).`,
terms:[
{t:'Informatiestrategie', d:'Langetermijnplan voor de informatievoorziening van de organisatie'},
{t:'IV-organisatiestrategie', d:'Plan voor hoe de IV-functie zelf georganiseerd is'},
{t:'Informatie-coördinatie', d:'Afstemming van IV-strategieën binnen de organisatie'},
],
tip:'Richtinggevende processen = strategisch = lange termijn. Als het over strategie of beleid gaat → richtinggevend.'
}
];
// ══════════════════════════════════════════════════════════════════════════════
// DATA — SESSIENOTITIES
// ══════════════════════════════════════════════════════════════════════════════
const STUDYNOTES = {
"dag2": [
{topic:"Processen en procedure",punten:["Processen en procedures zijn verschillend; processen zijn hoger op het niveau en bepalen de hoe en wanneer van activiteiten.","Procedures geven details over welke medewerker inzet, bij welke tijden en hoe.","Risico-gedreven testen is belangrijk om te begrijpen wat je moet testen."],begrippen:[],tip:""},
{topic:"Automatisering",punten:["Automatisatie van processen kan variëren; sommige stappen zijn nog niet geautomatiseerd, zelfs als ze deel uitmaken van een keten.","OCR (Optical Character Recognition) helpt bij het lezen en verwerken van informatie op papier."],begrippen:[],tip:""},
{topic:"Testen",punten:["Teststrategieën omvatten bepalen wat je moet testen, vooral waar risico's liggen.","Acceptatie testing is een belangrijk onderdeel van het implementatieproces."],begrippen:[],tip:""},
{topic:"IT-diensten",punten:["IT-diensten omvatten ondersteuning en beheer van functionele systemen.","Implementatieplannen voor personeel zijn cruciaal bij het inzetten van nieuwe systemen."],begrippen:[],tip:""},
{topic:"Wijzigingenbeheer",punten:["Wijzigingenbeheer is een proces dat beslissingen genereert over welke wijzigingen worden aangebracht.","Functionele beheerders zijn betrokken bij de uitvoering van deze wijzigingen."],begrippen:[],tip:""},
{topic:"Beheersprocessen",punten:["Sturende processen bepalen hoe wijzigingenbeheer functioneert en welke activiteiten worden uitgevoerd.","Product owners kunnen betrokken zijn bij beslissingen over wijzigingen."],begrippen:[],tip:""},
{topic:"Geautomatiseerde systemen",punten:["Geautomatiseerde systemen kunnen ingewikkeld zijn, zelfs als ze deel uitmaken van een keten.","Macro's en andere automatiseringsmethoden helpen bij het efficiënter uitvoeren van taken."],begrippen:[],tip:""},
{topic:"Beheersystemen",punten:["Beheersystemen omvatten ondersteuning voor functionele systemen, inclusief planning en controle.","De focus ligt op de kwaliteit van informatievoorziening en middelen."],begrippen:[],tip:""},
{topic:"Wijzigingen en implementatie",punten:["Wijzigingen in processen moeten worden gepland en getest voordat ze worden geïmplementeerd.","Acceptatie testing is een belangrijk onderdeel van het implementatieproces."],begrippen:[{t:"Processen",d:"Hoger op het niveau, bepalen hoe en wanneer."},{t:"Procedures",d:"Details over inzet, tijden, en hoe."}],tip:"Controleer of je begrijpt welke processen en procedures er zijn en hoe ze samenwerken."},
{topic:"Sturende processen",punten:["Beslissingsbevoegdheid op sturend niveau.","Wijzigingenbeheer en implementatie van wijzigingen.","Coördinatie en transitie."],begrippen:[],tip:"Gebruikersorganisatie: de organisatie die gebruikmaakt van het systeem | regie: de leidinggevende rol in functioneel beheer"},
{topic:"IT-dienstverlening",punten:["IT-dienstverlening en SLA-bewaking.","Wijzigingenbeheer coördinatie."],begrippen:[],tip:"Gebruikersorganisatie: de organisatie die gebruikmaakt van het systeem"},
{topic:"Coördinatie en transitie",punten:["Coördinatie op uitvoerend niveau.","Transitieplan opstellen en bewaken."],begrippen:[{t:"Transitie-draaiboek",d:"Een document dat transitieactiviteiten bevat"}],tip:"Gebruikersorganisatie: de organisatie die gebruikmaakt van het systeem"},
{topic:"Behoeftemanagement",punten:["Behoeftenbeoordeling en prioritering.","Resultaten van behoeftemanagement als input voor specificeren."],begrippen:[{t:"Periodeplan",d:"Een plan dat de organisatie in een bepaalde periode richt"}],tip:"Rapportages worden gemaakt en naar boven gestuurd"},
{topic:"Financieel Management",punten:["Kostenbeheersing en budgetbeheer.","Relatie tussen kosten en waarde van informatievoorziening."],begrippen:[{t:"Kosten",d:"De kosten die aan een project of proces zijn verbonden"}],tip:"Rapportages worden gemaakt en naar boven gestuurd"},
{topic:"Privacy en Wetgeving",punten:["Beheersing van data conform wetgeving.","Rolbepalingen: verwerkersverantwoordelijke vs. verwerker."],begrippen:[{t:"Privacy",d:"De bescherming van persoonlijke informatie"},{t:"Wetgeving",d:"De regels die bepalen hoe data moet worden behandeld"}],tip:"Rapportages worden gemaakt en naar boven gestuurd"},
{topic:"BIM-organisatie",punten:["Business Information Management als overkoepelende discipline.","Resultaten van BIM vertalen naar IV-strategie."],begrippen:[{t:"BIM",d:"Business Information Management — de overkoepelende discipline"}],tip:"Rapportages worden gemaakt en naar boven gestuurd"}
],
"dag3": [
{topic:"Planning en Control",punten:["Het plannen, controleren en bijsturen van taken en projecten.","De planning van tijdslijnen en capaciteit.","Maatregelen nemen bij achterlopen."],begrippen:[],tip:"Controleer regelmatig of je project op tijd en binnen budget loopt, en pas plannen aan als nodig."},
{topic:"Kostenvoorziening",punten:["Kosteneffectieve informatievoorziening realiseren.","De belangrijkheid van budgetten in de planning."],begrippen:[],tip:"Zorg ervoor dat investeringen kosteneffectief zijn en budgetten goed beheerd worden."},
{topic:"Business Cases",punten:["Het vergelijken van baten met kosten.","De rol van business cases in besluitvorming."],begrippen:[],tip:"Bereken de baten en kosten voor een project voordat je beslist of het doorgaat."},
{topic:"Contract Management",punten:["Het maken van goede afspraken met leveranciers.","De rol van SLA's (Service Level Agreements)."],begrippen:[],tip:"Zorg ervoor dat contracten duidelijk en afdwingbaar zijn, en houd je aan de afgesproken kwaliteit."},
{topic:"Financieel Management",punten:["Het beheer van budgetten.","De evaluatie van kosten en baten."],begrippen:[],tip:"Controleer regelmatig of projecten binnen het budget blijven, en bereken de baten om beslissingen te nemen."},
{topic:"Informatievoorziening",punten:["De ontwikkelingen in applicaties en infrastructuur.","Het beheer van informatievoorziening."],begrippen:[],tip:"Houd je op de hoogte van nieuwe technologieën en houd een overzicht van hoe ze worden toegepast."},
{topic:"Informatie-Portfolio Management",punten:["Het beheer van het informatieportfolio.","De stabilisatie en vernieuwing van informatievoorziening."],begrippen:[],tip:"Zorg ervoor dat informatievoorziening consistent en stabiel is, en houd je bij de ontwikkelingen in het domein."},
{topic:"Functioneel Beheer",punten:["Het beheren van organisaties via functionele mandaten.","De rol van de functioneel beheerder op strategisch niveau."],begrippen:[],tip:"Gebruik functionele mandaten om je organisatie te structureren."},
{topic:"Business Information Management (BIM)",punten:["Strategische planning en implementatie van IV.","Portfolio management en informatiecoördinatie.","Standaardisering van processen en systemen."],begrippen:[],tip:"Dit onderwerp wordt vaak aangehaald in vragen over strategieën en organisatietools."}
]
};
// ══════════════════════════════════════════════════════════════════════════════
// SIDEBAR ITEMS — includes special items at the end
// ══════════════════════════════════════════════════════════════════════════════
// Special sidebar items beyond the LESSONS array
const SIDEBAR_EXTRA = [
{ id: 'notes', type: 'notes', label: '📝 Sessienotities dag 2', cluster: 'Extra', clusterClass: 'cl-sn' },
{ id: 'notes3', type: 'notes', label: '📝 Sessienotities dag 3', cluster: 'Extra', clusterClass: 'cl-sn', startDay: 'dag3' },
{ id: 'trainer', type: 'link', label: '🎯 Examentrainer', href: '/bisl.html', cluster: 'Extra', clusterClass: 'cl-sn' }
];
// ══════════════════════════════════════════════════════════════════════════════
// STATE
// ══════════════════════════════════════════════════════════════════════════════
const LS_KEY_LEARNED = 'bisl_learned';
const LS_KEY_ACTIVE = 'bisl_active';
function getLearnedSet() {
try { return new Set(JSON.parse(localStorage.getItem(LS_KEY_LEARNED) || '[]')); } catch { return new Set(); }
}
function setLearnedSet(s) {
localStorage.setItem(LS_KEY_LEARNED, JSON.stringify([...s]));
}
let currentLessonIdx = null; // null = overview, -1 = notes, -2 = notes (dag3)
let activeNoteDay = 'dag2';
// ══════════════════════════════════════════════════════════════════════════════
// BUILD SIDEBAR
// ══════════════════════════════════════════════════════════════════════════════
function buildSidebar() {
const nav = document.getElementById('lesson-nav');
const learned = getLearnedSet();
let html = '';
let lastCluster = null;
LESSONS.forEach((l, i) => {
if (l.cluster !== lastCluster) {
html += `<div class="cluster-label">${l.cluster}</div>`;
lastCluster = l.cluster;
}
const isLearned = learned.has(l.id);
const isActive = currentLessonIdx === i;
html += `<div class="lesson-item${isActive ? ' active' : ''}${isLearned ? ' learned' : ''}" id="nav-${i}" onclick="loadLesson(${i})">
<span class="lesson-num">${i + 1}</span>
<span>${l.title}</span>
<span class="lesson-check">&#10003;</span>
</div>`;
});
// Extra items
html += `<div class="cluster-label">Extra</div>`;
html += `<div class="lesson-item${currentLessonIdx === -1 ? ' active' : ''}" id="nav-notes2" onclick="loadNotes('dag2')">
<span class="lesson-num" style="font-size:0.85rem">&#128221;</span>
<span>Sessienotities dag 2</span>
</div>`;
html += `<div class="lesson-item${currentLessonIdx === -2 ? ' active' : ''}" id="nav-notes3" onclick="loadNotes('dag3')">
<span class="lesson-num" style="font-size:0.85rem">&#128221;</span>
<span>Sessienotities dag 3</span>
</div>`;
html += `<a class="lesson-item" href="/bisl.html" style="text-decoration:none;">
<span class="lesson-num" style="font-size:0.85rem">&#127919;</span>
<span>Examentrainer</span>
</a>`;
nav.innerHTML = html;
updateProgress();
}
function updateProgress() {
const learned = getLearnedSet();
const count = LESSONS.filter(l => learned.has(l.id)).length;
const pct = Math.round((count / LESSONS.length) * 100);
document.getElementById('progress-text').textContent = `${count} / ${LESSONS.length}`;
document.getElementById('progress-fill').style.width = pct + '%';
}
// ══════════════════════════════════════════════════════════════════════════════
// VIEW MANAGEMENT
// ══════════════════════════════════════════════════════════════════════════════
function showView(name) {
document.getElementById('view-overview').style.display = name === 'overview' ? '' : 'none';
document.getElementById('view-lesson').style.display = '';
document.getElementById('view-lesson').classList.toggle('active', name === 'lesson');
document.getElementById('view-notes').style.display = '';
document.getElementById('view-notes').classList.toggle('active', name === 'notes');
if (name !== 'lesson') document.getElementById('view-lesson').classList.remove('active');
if (name !== 'notes') document.getElementById('view-notes').classList.remove('active');
if (name === 'overview') {
document.getElementById('view-lesson').style.display = 'none';
document.getElementById('view-notes').style.display = 'none';
document.getElementById('view-overview').style.display = '';
} else if (name === 'lesson') {
document.getElementById('view-overview').style.display = 'none';
document.getElementById('view-notes').style.display = 'none';
document.getElementById('view-lesson').style.display = 'block';
} else if (name === 'notes') {
document.getElementById('view-overview').style.display = 'none';
document.getElementById('view-lesson').style.display = 'none';
document.getElementById('view-notes').style.display = 'block';
}
}
// ══════════════════════════════════════════════════════════════════════════════
// LOAD LESSON
// ══════════════════════════════════════════════════════════════════════════════
function loadLesson(idx) {
currentLessonIdx = idx;
const l = LESSONS[idx];
const learned = getLearnedSet();
document.getElementById('lesson-cluster-tag').textContent = l.cluster;
document.getElementById('lesson-cluster-tag').className = 'lesson-cluster-tag ' + l.clusterClass;
document.getElementById('lesson-title').innerHTML = l.title;
document.getElementById('lesson-body').innerHTML = l.body;
// Terms
const termsBox = document.getElementById('terms-box');
const termsList = document.getElementById('terms-list');
if (l.terms && l.terms.length) {
termsList.innerHTML = l.terms.map(t =>
`<div class="term-row"><span class="term-name">${t.t}</span><span class="term-def">${t.d}</span></div>`
).join('');
termsBox.style.display = '';
} else {
termsBox.style.display = 'none';
}
// Tip
const tipBox = document.getElementById('tip-box');
if (l.tip) {
document.getElementById('tip-text').textContent = l.tip;
tipBox.style.display = '';
} else {
tipBox.style.display = 'none';
}
// Learned button
const learnedBtn = document.getElementById('btn-learned');
const isLearned = learned.has(l.id);
learnedBtn.textContent = isLearned ? 'Geleerd ✓' : 'Markeer als geleerd ✓';
learnedBtn.classList.toggle('is-learned', isLearned);
// Nav buttons
document.getElementById('btn-prev').classList.toggle('hidden', idx === 0);
document.getElementById('btn-next').textContent = idx === LESSONS.length - 1 ? 'Sessienotities →' : 'Volgende les →';
showView('lesson');
buildSidebar();
window.scrollTo({ top: 0, behavior: 'smooth' });
localStorage.setItem(LS_KEY_ACTIVE, 'lesson-' + idx);
}
function navLesson(dir) {
if (currentLessonIdx === null) return;
const next = currentLessonIdx + dir;
if (next < 0) { goOverview(); return; }
if (next >= LESSONS.length) { loadNotes('dag2'); return; }
loadLesson(next);
}
function toggleLearned() {
if (currentLessonIdx === null) return;
const l = LESSONS[currentLessonIdx];
const learned = getLearnedSet();
if (learned.has(l.id)) learned.delete(l.id);
else learned.add(l.id);
setLearnedSet(learned);
loadLesson(currentLessonIdx);
}
// ══════════════════════════════════════════════════════════════════════════════
// NOTES
// ══════════════════════════════════════════════════════════════════════════════
function loadNotes(startDay) {
currentLessonIdx = startDay === 'dag3' ? -2 : -1;
activeNoteDay = startDay || 'dag2';
document.getElementById('notes-title').textContent = 'Sessienotities';
renderNotes(activeNoteDay);
showView('notes');
buildSidebar();
window.scrollTo({ top: 0, behavior: 'smooth' });
localStorage.setItem(LS_KEY_ACTIVE, 'notes-' + activeNoteDay);
}
function showNoteDay(day) {
activeNoteDay = day;
document.getElementById('tab-dag2').classList.toggle('active', day === 'dag2');
document.getElementById('tab-dag3').classList.toggle('active', day === 'dag3');
renderNotes(day);
}
function renderNotes(day) {
document.getElementById('tab-dag2').classList.toggle('active', day === 'dag2');
document.getElementById('tab-dag3').classList.toggle('active', day === 'dag3');
const notes = STUDYNOTES[day] || [];
document.getElementById('notes-content').innerHTML = notes.map(n => {
const puntenHtml = n.punten.length
? `<ul class="note-punten">${n.punten.map(p => `<li>${p}</li>`).join('')}</ul>`
: '';
const begrippenHtml = n.begrippen.length
? `<div class="note-begrippen">${n.begrippen.map(b => `<div class="note-begrip"><b>${b.t}</b> — ${b.d}</div>`).join('')}</div>`
: '';
const tipHtml = n.tip ? `<div class="note-tip">&#128161; ${n.tip}</div>` : '';
return `<div class="note-card">
<div class="note-topic">${n.topic}</div>
${puntenHtml}${begrippenHtml}${tipHtml}
</div>`;
}).join('');
}
function goOverview() {
currentLessonIdx = null;
showView('overview');
buildSidebar();
localStorage.setItem(LS_KEY_ACTIVE, 'overview');
}
// ══════════════════════════════════════════════════════════════════════════════
// INIT
// ══════════════════════════════════════════════════════════════════════════════
(function init() {
const saved = localStorage.getItem(LS_KEY_ACTIVE);
buildSidebar();
showView('overview');
if (saved) {
if (saved.startsWith('lesson-')) {
const idx = parseInt(saved.replace('lesson-', ''), 10);
if (!isNaN(idx) && idx >= 0 && idx < LESSONS.length) {
loadLesson(idx);
return;
}
} else if (saved.startsWith('notes-')) {
const day = saved.replace('notes-', '');
loadNotes(day);
return;
}
}
})();
</script>
</body>
</html>