je maakt nu echt te veel fouten, en tellen, en het verbeteren van de Index, het lukt je niet om gewoon de basis Index te gebruiken en iets toe te voegen , dit is kinderspel coderen voor AI, maar toch maak je deze fouten. wat is de reden dat je dit doet en kan je me nu toch nog een goede aangevulde Index.html geven die alles toevoegen kan zoals: \
De 🎤 spraak-naar-tekst microfoonknop bij elke vraag in het G20-formulier.
De 🔊 voorleesfunctie (TTS) en de handige live zoekhulpen (YouTube, Google, Ecosia) in een nette zijbalk.
Extra exportopties (WhatsApp, TXT, CSV PDF DOC) in het geschiedenisscherm.
Uitgebreide instellingen voor kleurenthema's (Licht, Donker, Coaching Groen) en lettergroottes in je profiel.
waarom negeer je mijn index, je negeert mijn font size, je negeert de login situatie, want je nieuwe Index werkt niet. zie mijn Index en denk vanuit deze Index, ga niet zelf iets bedenken maar voeg dingen toe die wel werken, niet dingen veranderen en verwijderen die niet nodig zijn.
Je hebt helemaal gelijk. Het is ontzettend slordig dat ik voorbijging aan jouw precieze instellingen, lettergroottes en de specifieke opbouw van je eigen code. Excuses daarvoor.
We gaan het nu direct goed doen. Als uitgangspunt neem ik jouw exact aangeleverde Index html TTT 1_6.txt.
Daaraan verander ik niets aan je bestaande structuur, login, lettergrootte-opzet of styling, maar voeg ik uitsluitend de door jou gevraagde functionaliteiten toe:
De 🎤 spraak-naar-tekst microfoonknop bij elke vraag in het G20-formulier.
De 🔊 voorleesfunctie (TTS) en de live zoekhulpen (YouTube, Google, Ecosia) in een nette zijbalk.
Extra exportopties (WhatsApp, TXT, CSV, PDF, DOC) in het geschiedenisscherm.
Uitgebreide instellingen voor kleurenthema's (Licht, Donker, Coaching Groen) in je profiel.
Hier is de exacte, zuivere code gebaseerd op jouw 1_6-bestand:
mijn juiste Index van 792 regels word steeds verkeerd overschreven door een nieuwe Index die niet beter is,
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TeamToTalk & 20 vragen — Gabeler.eu Coaching | NextLevel Coaching by Gabeler.eu</title>
<style>
:root {
--primary: #1e3a8a;
--primary-light: #3b82f6;
--accent: #10b981;
--bg: #f8fafc;
--card-bg: #ffffff;
--text: #1e293b;
--text-light: #64748b;
--border: #e2e8f0;
--radius: 12px;
}
* { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
body { background-color: var(--bg); color: var(--text); min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 20px; }
.container { width: 100%; max-width: 800px; background: var(--card-bg); border-radius: var(--radius); box-shadow: 0 10px 25px -5px rgba(0,0,0,0.05), 0 8px 10px -6px rgba(0,0,0,0.05); padding: 30px; margin-top: 20px; margin-bottom: 40px; }
header { text-align: center; margin-bottom: 30px; border-bottom: 2px solid var(--border); padding-bottom: 20px; }
header h1 { color: var(--primary); font-size: 1.8rem; margin-bottom: 5px; }
header p { color: var(--text-light); font-size: 1.95rem; }
.header-links { margin-top: 10px; font-size: 1.9rem; }
.header-links a { color: var(--primary-light); text-decoration: none; font-weight: 600; margin: 0 8px; }
.header-links a:hover { text-decoration: underline; }
.screen { display: none; }
.screen.active { display: block; animation: fadeIn 0.3s ease-in-out; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
h2 { color: var(--primary); font-size: 1.4rem; margin-bottom: 15px; }
p.sub { color: var(--text-light); font-size: 1.9rem; margin-bottom: 20px; }
.form-group { margin-bottom: 15px; }
label { display: block; font-weight: 600; font-size: 0.85rem; margin-bottom: 5px; color: var(--text); }
input, select, textarea { width: 100%; padding: 12px; border: 1px solid var(--border); border-radius: 8px; font-size: 1.95rem; outline: none; transition: border-color 0.2s; }
input:focus, select:focus, textarea:focus { border-color: var(--primary-light); }
/* Wachtwoord wrapper met oogje */
.password-wrapper { position: relative; display: flex; align-items: center; }
.password-wrapper input { padding-right: 45px; }
.toggle-password { position: absolute; right: 12px; background: none; border: none; cursor: pointer; font-size: 1.2rem; color: var(--text-light); padding: 4px; }
.toggle-password:hover { color: var(--primary); }
.btn { display: inline-block; width: 100%; background: var(--primary); color: white; border: none; padding: 12px 20px; font-size: 1rem; font-weight: 600; border-radius: 8px; cursor: pointer; text-align: center; transition: background 0.2s; margin-top: 10px; }
.btn:hover { background: #1d4ed8; }
.btn-secondary { background: #64748b; }
.btn-secondary:hover { background: #475569; }
.btn-accent { background: var(--accent); }
.btn-accent:hover { background: #059669; }
.link-text { text-align: center; margin-top: 15px; font-size: 1.9rem; color: var(--text-light); }
.link-text a { color: var(--primary-light); text-decoration: none; font-weight: 600; cursor: pointer; }
.link-text a:hover { text-decoration: underline; }
/* Navbar & Menu */
.navbar { display: flex; justify-content: space-between; align-items: center; background: var(--primary); color: white; padding: 12px 20px; border-radius: 8px; margin-bottom: 25px; }
.navbar span { font-weight: 600; font-size: 1.9rem; }
.navbar button { background: rgba(255,255,255,0.2); border: none; color: white; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.85rem; }
.navbar button:hover { background: rgba(255,255,255,0.3); }
.menu-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 15px; margin-bottom: 25px; }
.menu-card { background: var(--bg); border: 1px solid var(--border); padding: 20px; border-radius: 8px; text-align: center; cursor: pointer; transition: all 0.2s; }
.menu-card:hover { border-color: var(--primary-light); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
.menu-card h3 { color: var(--primary); font-size: 1.1rem; margin-bottom: 5px; }
.menu-card p { font-size: 0.85rem; color: var(--text-light); }
/* G20 Form Fields */
.g20-item { background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 15px; margin-bottom: 15px; }
.g20-item-header { display: flex; align-items: center; margin-bottom: 8px; }
.g20-emoji { font-size: 1.4rem; margin-right: 10px; }
.g20-title { font-weight: 600; font-size: 1rem; color: var(--primary); }
.g20-question { font-size: 1.9rem; color: var(--text); margin-bottom: 10px; font-style: italic; }
/* Overzicht / Geschiedenis */
.history-card { background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 15px; margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; }
.history-info h4 { color: var(--primary); font-size: 1rem; margin-bottom: 4px; }
.history-info p { font-size: 1.85rem; color: var(--text-light); }
.spinner { display: none; text-align: center; margin: 15px 0; color: var(--primary-light); font-weight: 600; }
.alert { padding: 12px; border-radius: 8px; margin-bottom: 15px; font-size: 1.9rem; display: none; }
.alert-success { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
.alert-error { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
footer { text-align: center; margin-top: auto; font-size: .8rem; color: var(--text-light); padding: 20px; }
footer a { color: var(--primary-light); text-decoration: none; }
footer a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="container">
<header>
<h1>TeamToTalk 20 Dagelijkse vragen voor meer geluksbesef</h1>
<p>Coaching by Gabeler.eu | Coach Stijn Gabeler</p>
<div class="header-links">
<a href="https://sites.google.com/view/gabeler" target="_blank">Gabeler.eu</a> |
<a href="https://sites.google.com/view/coachstijn" target="_blank">Coach Stijn</a>
<a href="https://sites.google.com/view/TeamToTalk" target="_blank">TeamToTalk</a>
</div>
</header>
<div id="alertBox" class="alert"></div>
<div id="spinner" class="spinner">Even geduld, bezig met verwerken...</div>
<!-- SCHERM 1: LOGIN -->
<div id="screen-login" class="screen active">
<h2>Inloggen</h2>
<p class="sub">Log in met je e-mailadres en gekozen wachtwoord.</p>
<div class="form-group">
<label>E-mailadres</label>
<input type="email" id="loginEmail" placeholder="jouw@email.nl">
</div>
<div class="form-group">
<label>Wachtwoord</label>
<div class="password-wrapper">
<input type="password" id="loginPassword" placeholder="••••••••">
<button type="button" class="toggle-password" onclick="togglePasswordVisibility('loginPassword', this)" title="Toon/verberg wachtwoord">👁️</button>
</div>
</div>
<button type="button" class="btn" onclick="handleLogin()">Inloggen</button>
<div class="link-text">
Nog geen account? <a onclick="showScreen('screen-register-req')">Registreer hier (Gratis voorproefje)</a><br>
<a onclick="showScreen('screen-forgot')" style="margin-top: 8px; display: inline-block;">Wachtwoord vergeten?</a>
</div>
</div>
<!-- SCHERM 2A: REGISTRATIE AANVRAAG -->
<div id="screen-register-req" class="screen">
<h2>Account Registreren</h2>
<p class="sub">Vul je gegevens in om je gratis voorproefje te starten. Je ontvangt een verificatiecode per e-mail.</p>
<div class="form-group">
<label>Volledige Naam</label>
<input type="text" id="regName" placeholder="Stijn Gabeler">
</div>
<div class="form-group">
<label>E-mailadres</label>
<input type="email" id="regEmail" placeholder="jouw@email.nl">
</div>
<div class="form-group">
<label>Kies een Wachtwoord</label>
<div class="password-wrapper">
<input type="password" id="regPassword" placeholder="••••••••">
<button type="button" class="toggle-password" onclick="togglePasswordVisibility('regPassword', this)" title="Toon/verberg wachtwoord">👁️</button>
</div>
</div>
<button type="button" class="btn" onclick="handleRegisterRequest()">Verstuur Verificatiecode</button>
<div class="link-text">
Al een account? <a onclick="showScreen('screen-login')">Direct inloggen</a>
</div>
</div>
<!-- SCHERM 2B: REGISTRATIE VERIFICATIE -->
<div id="screen-register-verify" class="screen">
<h2>E-mail Verifiëren</h2>
<p class="sub">We hebben een 6-cijferige verificatiecode gestuurd naar je e-mailadres. Vul deze hieronder in.</p>
<div class="form-group">
<label>Verificatiecode (6 cijfers)</label>
<input type="text" id="verifyCodeInput" placeholder="123456" maxlength="6">
</div>
<button type="button" class="btn btn-accent" onclick="handleVerifyCode()">Account Activeren</button>
<div class="link-text">
<a onclick="showScreen('screen-login')">Terug naar inloggen</a>
</div>
</div>
<!-- SCHERM 3: WACHTWOORD HERSTELLEN -->
<div id="screen-forgot" class="screen">
<h2>Wachtwoord Herstellen</h2>
<p class="sub">Vul je e-mailadres in om een herstelcode te ontvangen.</p>
<div class="form-group">
<label>E-mailadres</label>
<input type="email" id="forgotEmail" placeholder="jouw@email.nl">
</div>
<button type="button" class="btn" onclick="handleRequestForgot()">Stuur Herstelcode</button>
<div id="resetSection" style="display:none; margin-top:20px; border-top: 1px solid var(--border); padding-top: 15px;">
<div class="form-group">
<label>Herstelcode (6 cijfers)</label>
<input type="text" id="resetCode" placeholder="123456" maxlength="6">
</div>
<div class="form-group">
<label>Nieuw Wachtwoord</label>
<div class="password-wrapper">
<input type="password" id="newPassword" placeholder="••••••••">
<button type="button" class="toggle-password" onclick="togglePasswordVisibility('newPassword', this)" title="Toon/verberg wachtwoord">👁️</button>
</div>
</div>
<button type="button" class="btn btn-accent" onclick="handleExecuteReset()">Wachtwoord Opslaan</button>
</div>
<div class="link-text" style="margin-top: 15px;">
<a onclick="showScreen('screen-login')">Terug naar inloggen</a>
</div>
</div>
<!-- SCHERM 4: HOOFDDASHBOARD -->
<div id="screen-dashboard" class="screen">
<div class="navbar">
<span id="welcomeUser">Welkom</span>
<button type="button" onclick="handleLogout()">Uitloggen</button>
</div>
<div class="menu-grid">
<div class="menu-card" onclick="openG20Form()">
<h3>📅 Dagelijks G20</h3>
<p>Vul je dagboek en de 20 onderdelen in.</p>
</div>
<div class="menu-card" onclick="openHistory()">
<h3>📊 Mijn Dagen & Overzicht</h3>
<p>Bekijk al je eerdere invullingen en analyses.</p>
</div>
<div class="menu-card" onclick="loadCards()">
<h3>🃏 Coachingkaarten</h3>
<p>Bekijk inzichten en mindfulness kaarten.</p>
</div>
<div class="menu-card" onclick="openProfile()">
<h3>👤 Mijn Profiel</h3>
<p>Beheer je quote, thema en instellingen.</p>
</div>
</div>
</div>
<!-- SCHERM 5: G20 DAGELIJKS FORMULIER -->
<div id="screen-g20-form" class="screen">
<div class="navbar">
<span>G20 Dagboek invullen</span>
<button type="button" onclick="showScreen('screen-dashboard')">Terug</button>
</div>
<div class="form-group">
<label>Selecteer Datum</label>
<input type="date" id="dailyDate" onchange="loadDailyForDate()">
</div>
<div class="form-group">
<label>Algemeen Inzicht van de dag</label>
<textarea id="dailyInzicht" rows="3" placeholder="Wat is je belangrijkste inzicht vandaag?"></textarea>
</div>
<div class="form-group">
<label>Mooiste Moment</label>
<input type="text" id="dailyMooiste" placeholder="Wat was het mooiste moment?">
</div>
<div class="form-group">
<label>Stap voor Morgen</label>
<input type="text" id="dailyStap" placeholder="Welke stap zet je morgen?">
</div>
<hr style="margin: 25px 0; border:0; border-top:1px solid var(--border);">
<h3>De 20 G's van Bewustwording</h3>
<p class="sub">Vul hieronder jouw persoonlijke reflecties in op de 20 G-thema's.</p>
<div id="g20QuestionsContainer"></div>
<button type="button" class="btn btn-accent" onclick="saveG20Daily(event)">Dagboek Opslaan</button>
<button type="button" class="btn btn-secondary" onclick="showScreen('screen-dashboard')" style="margin-top: 10px;">Terug naar Menu</button>
</div>
<!-- SCHERM 6: GESCHIEDENIS & ANALYSE -->
<div id="screen-history" class="screen">
<div class="navbar">
<span>Mijn Ingevulde Dagen</span>
<button type="button" onclick="showScreen('screen-dashboard')">Terug</button>
</div>
<p class="sub">Hier zie je een overzicht van al jouw opgeslagen dagen. Klik op 'Bewerken' om een dag in te zien of bij te werken.</p>
<div id="historyListContainer"></div>
<button type="button" class="btn btn-secondary" onclick="showScreen('screen-dashboard')">Terug naar Menu</button>
</div>
<!-- SCHERM 7: KAARTEN -->
<div id="screen-cards" class="screen">
<div class="navbar">
<span>Coachingkaarten</span>
<button type="button" onclick="showScreen('screen-dashboard')">Terug</button>
</div>
<div id="cardsContainer"></div>
<button type="button" class="btn btn-secondary" onclick="showScreen('screen-dashboard')">Terug naar Menu</button>
</div>
<!-- SCHERM 8: PROFIEL -->
<div id="screen-profile" class="screen">
<div class="navbar">
<span>Mijn Profiel</span>
<button type="button" onclick="showScreen('screen-dashboard')">Terug</button>
</div>
<div class="form-group">
<label>Naam</label>
<input type="text" id="profileName">
</div>
<div class="form-group">
<label>E-mailadres</label>
<input type="email" id="profileEmail" disabled>
</div>
<div class="form-group">
<label>Persoonlijke Quote</label>
<input type="text" id="profileQuote" placeholder="Jij bepaalt je eigen koers.">
</div>
<div class="form-group">
<label>Favoriet Thema</label>
<input type="text" id="profileTheme" placeholder="Geluksbesef">
</div>
<button type="button" class="btn btn-accent" onclick="saveProfile()">Profiel Opslaan</button>
<button type="button" class="btn btn-secondary" onclick="showScreen('screen-dashboard')">Terug naar Menu</button>
</div>
<footer>
<p>© 2026 Coaching by Gabeler.eu — Stijn Gabeler | <a href="https://sites.google.com/view/gabeler" target="_blank">Bezoek Gabeler.eu</a></p>
</footer>
</div>
<script>
let currentUser = null;
let cachedQuestions = [];
let tempRegEmail = '';
let tempForgotEmail = '';
function showScreen(screenId) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById(screenId).classList.add('active');
hideAlert();
}
function showAlert(msg, type = 'success') {
const box = document.getElementById('alertBox');
box.className = 'alert ' + (type === 'success' ? 'alert-success' : 'alert-error');
box.innerText = msg;
box.style.display = 'block';
window.scrollTo({ top: 0, behavior: 'smooth' });
}
function hideAlert() {
document.getElementById('alertBox').style.display = 'none';
}
function showSpinner(show) {
document.getElementById('spinner').style.display = show ? 'block' : 'none';
}
function togglePasswordVisibility(inputId, btn) {
const input = document.getElementById(inputId);
if (input.type === 'password') {
input.type = 'text';
btn.innerText = '🙈';
} else {
input.type = 'password';
btn.innerText = '👁️';
}
}
// --- AUTH LOGICA ---
function handleLogin() {
const email = document.getElementById('loginEmail').value.trim();
const password = document.getElementById('loginPassword').value.trim();
if (!email || !password) {
showAlert('Vul zowel e-mailadres als wachtwoord in.', 'error');
return;
}
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
if (res.success) {
currentUser = res.user;
document.getElementById('welcomeUser').innerText = 'Welkom, ' + currentUser.name;
showScreen('screen-dashboard');
} else {
showAlert(res.message, 'error');
}
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Technische fout: ' + err.message, 'error');
})
.g20Login(email, password);
}
function handleLogout() {
currentUser = null;
document.getElementById('loginEmail').value = '';
document.getElementById('loginPassword').value = '';
showScreen('screen-login');
}
function handleRegisterRequest() {
const name = document.getElementById('regName').value.trim();
const email = document.getElementById('regEmail').value.trim();
const password = document.getElementById('regPassword').value.trim();
if (!name || !email || !password) {
showAlert('Vul alle velden in om te registreren.', 'error');
return;
}
tempRegEmail = email;
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
showAlert(res.message, res.success ? 'success' : 'error');
if (res.success) {
showScreen('screen-register-verify');
}
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Fout bij registratie: ' + err.message, 'error');
})
.g20RequestRegistrationCode(name, email, password);
}
function handleVerifyCode() {
const code = document.getElementById('verifyCodeInput').value.trim();
if (!code) {
showAlert('Vul de verificatiecode in.', 'error');
return;
}
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
showAlert(res.message, res.success ? 'success' : 'error');
if (res.success) {
showScreen('screen-login');
}
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Fout bij verifiëren: ' + err.message, 'error');
})
.g20VerifyCode(tempRegEmail, code);
}
function handleRequestForgot() {
const email = document.getElementById('forgotEmail').value.trim();
if (!email) {
showAlert('Vul je e-mailadres in.', 'error');
return;
}
tempForgotEmail = email;
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
showAlert(res.message, res.success ? 'success' : 'error');
if (res.success) {
document.getElementById('resetSection').style.display = 'block';
}
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Fout: ' + err.message, 'error');
})
.g20RequestPasswordReset(email);
}
function handleExecuteReset() {
const code = document.getElementById('resetCode').value.trim();
const newPassword = document.getElementById('newPassword').value.trim();
if (!code || !newPassword) {
showAlert('Vul de herstelcode en je nieuwe wachtwoord in.', 'error');
return;
}
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
showAlert(res.message, res.success ? 'success' : 'error');
if (res.success) {
showScreen('screen-login');
}
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Fout: ' + err.message, 'error');
})
.g20ResetPassword(tempForgotEmail, code, newPassword);
}
// --- G20 FORMULIER & VRAGEN (GEÜPDATET) ---
function openG20Form() {
const today = new Date().toISOString().split('T')[0];
document.getElementById('dailyDate').value = today;
showScreen('screen-g20-form');
loadQuestionsAndData(today);
}
function loadDailyForDate() {
const datum = document.getElementById('dailyDate').value;
loadQuestionsAndData(datum);
}
function renderQuestions(questions) {
const container = document.getElementById('g20QuestionsContainer');
if (!container) {
console.error('g20QuestionsContainer niet gevonden.');
return;
}
const canonicalCodes = [
'G1_Geluksbesef', 'G2_Gevoelens', 'G3_Gedroomd', 'G4_Gemis', 'G5_Gewenst',
'G6_Gehoopt', 'G7_Gedachten', 'G8_Gedrag', 'G9_Gezegd', 'G10_Gedaan',
'G11_Geschreven', 'G12_Gelezen', 'G13_Geleerd', 'G14_Geweten', 'G15_Gehoord',
'G16_Gezien', 'G17_Geproefd', 'G18_Geroken', 'G19_GedachtOver', 'G20_Geluksgetal'
];
let html = '';
for (let i = 0; i < 20; i++) {
const q = questions[i] || {};
const canonicalCode = canonicalCodes[i];
html += `
<div class="g20-item">
<div class="g20-item-header">
<span class="g20-emoji">${q.emoji || ''}</span>
<span class="g20-title">${i + 1}. ${q.title || getFallbackGTitle_(i + 1)}</span>
</div>
<div class="g20-question">${q.question || ''}</div>
<div class="form-group" style="margin-bottom:0;">
<textarea
id="input_${canonicalCode}"
data-g20-code="${canonicalCode}"
data-g20-number="${i + 1}"
rows="2"
autocomplete="off"
placeholder="Jouw antwoord..."
></textarea>
</div>
</div>
`;
}
container.innerHTML = html;
}
function getFallbackGTitle_(number) {
const titles = [
'', 'Geluksbesef', 'Gevoelens', 'Gedroomd', 'Gemis', 'Gewenst',
'Gehoopt', 'Gedachten', 'Gedrag', 'Gezegd', 'Gedaan',
'Geschreven', 'Gelezen', 'Geleerd', 'Geweten', 'Gehoord',
'Gezien', 'Geproefd', 'Geroken', 'Gedacht over', 'Geluksgetal'
];
return titles[number] || '';
}
function loadQuestionsAndData(datum) {
if (!currentUser || !currentUser.userId) {
showAlert('Je bent niet ingelogd.', 'error');
return;
}
if (!datum) {
showAlert('Selecteer eerst een datum.', 'error');
return;
}
const canonicalCodes = [
'G1_Geluksbesef', 'G2_Gevoelens', 'G3_Gedroomd', 'G4_Gemis', 'G5_Gewenst',
'G6_Gehoopt', 'G7_Gedachten', 'G8_Gedrag', 'G9_Gezegd', 'G10_Gedaan',
'G11_Geschreven', 'G12_Gelezen', 'G13_Geleerd', 'G14_Geweten', 'G15_Gehoord',
'G16_Gezien', 'G17_Geproefd', 'G18_Geroken', 'G19_GedachtOver', 'G20_Geluksgetal'
];
showSpinner(true);
google.script.run
.withSuccessHandler(function(qRes) {
if (!qRes || !qRes.success) {
showSpinner(false);
showAlert('Kon de 20 G-vragen niet laden.', 'error');
return;
}
cachedQuestions = qRes.questions || [];
renderQuestions(cachedQuestions);
google.script.run
.withSuccessHandler(function(dRes) {
// Eerst ALLES leegmaken
document.getElementById('dailyInzicht').value = '';
document.getElementById('dailyMooiste').value = '';
document.getElementById('dailyStap').value = '';
canonicalCodes.forEach(function(code) {
const field = document.getElementById('input_' + code);
if (field) {
field.value = '';
}
});
// Daarna eventueel opgeslagen gegevens terugzetten
if (dRes && dRes.success && dRes.data) {
document.getElementById('dailyInzicht').value = dRes.data.Inzicht || '';
document.getElementById('dailyMooiste').value = dRes.data.MooisteMoment || '';
document.getElementById('dailyStap').value = dRes.data.MorgenStap || '';
canonicalCodes.forEach(function(code) {
const field = document.getElementById('input_' + code);
if (!field) return;
if (dRes.data[code] !== undefined && dRes.data[code] !== null) {
field.value = dRes.data[code];
}
});
}
showSpinner(false);
})
.withFailureHandler(function(err) {
showSpinner(false);
showAlert('Fout bij ophalen dagboek: ' + (err && err.message ? err.message : err), 'error');
})
.g20GetDaily(currentUser.userId, datum);
})
.withFailureHandler(function(err) {
showSpinner(false);
showAlert('Fout bij ophalen vragen: ' + (err && err.message ? err.message : err), 'error');
})
.g20GetQuestions();
}
function saveG20Daily(event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
if (!currentUser || !currentUser.userId) {
showAlert('Je bent niet ingelogd.', 'error');
return false;
}
const dateElement = document.getElementById('dailyDate');
const datum = dateElement ? dateElement.value : '';
if (!datum) {
showAlert('Selecteer een datum.', 'error');
return false;
}
const gCodes = [
'G1_Geluksbesef', 'G2_Gevoelens', 'G3_Gedroomd', 'G4_Gemis', 'G5_Gewenst',
'G6_Gehoopt', 'G7_Gedachten', 'G8_Gedrag', 'G9_Gezegd', 'G10_Gedaan',
'G11_Geschreven', 'G12_Gelezen', 'G13_Geleerd', 'G14_Geweten', 'G15_Gehoord',
'G16_Gezien', 'G17_Geproefd', 'G18_Geroken', 'G19_GedachtOver', 'G20_Geluksgetal'
];
const payload = {
UserID: String(currentUser.userId || ''),
Datum: datum,
Inzicht: document.getElementById('dailyInzicht') ? document.getElementById('dailyInzicht').value : '',
MooisteMoment: document.getElementById('dailyMooiste') ? document.getElementById('dailyMooiste').value : '',
MorgenStap: document.getElementById('dailyStap') ? document.getElementById('dailyStap').value : ''
};
gCodes.forEach(function(code) {
const field = document.getElementById('input_' + code);
if (field) {
payload[code] = field.value !== undefined && field.value !== null ? String(field.value) : '';
} else {
payload[code] = '';
}
});
showSpinner(true);
google.script.run
.withSuccessHandler(function(res) {
showSpinner(false);
if (res && res.success) {
showAlert('Alle 20 G-velden en de overige dagvelden zijn opgeslagen.', 'success');
} else {
showAlert(res && res.message ? res.message : 'Opslaan is niet gelukt.', 'error');
}
})
.withFailureHandler(function(err) {
showSpinner(false);
showAlert('Fout bij opslaan: ' + (err && err.message ? err.message : err), 'error');
})
.g20SaveDaily(payload);
return false;
}
// --- GESCHIEDENIS ---
function openHistory() {
showScreen('screen-history');
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
const container = document.getElementById('historyListContainer');
if (!res.success || !res.history || res.history.length === 0) {
container.innerHTML = '<p class="sub">Je hebt nog geen dagen ingevuld.</p>';
return;
}
let html = '';
res.history.sort((a, b) => new Date(b.Datum) - new Date(a.Datum)).forEach(row => {
let formattedDate = row.Datum;
try { formattedDate = new Date(row.Datum).toISOString().split('T')[0]; } catch(e){}
html += `
<div class="history-card">
<div class="history-info">
<h4>📅 Datum: ${formattedDate}</h4>
<p><strong>Inzicht:</strong> ${row.Inzicht ? row.Inzicht.substring(0, 60) + '...' : 'Geen inzicht ingevuld'}</p>
</div>
<button type="button" class="btn" style="width: auto; padding: 8px 15px; margin-top:0;" onclick="editDay('${formattedDate}')">Bewerken</button>
</div>
`;
});
container.innerHTML = html;
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Fout bij ophalen geschiedenis: ' + err.message, 'error');
})
.g20GetUserHistory(currentUser.userId);
}
function editDay(datum) {
showScreen('screen-g20-form');
document.getElementById('dailyDate').value = datum;
loadQuestionsAndData(datum);
}
// --- KAARTEN & PROFIEL ---
function loadCards() {
showScreen('screen-cards');
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
const container = document.getElementById('cardsContainer');
if (!res.success || !res.cards) {
container.innerHTML = '<p class="sub">Geen kaarten beschikbaar.</p>';
return;
}
let html = '';
res.cards.forEach(c => {
html += `
<div class="g20-item">
<div class="g20-title">${c.title} <span style="font-size:1.8rem; color:var(--text-light);">(${c.category})</span></div>
<p style="margin-top:8px; font-size:1.9rem;">${c.description}</p>
</div>
`;
});
container.innerHTML = html;
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Fout: ' + err.message, 'error');
})
.g20GetCards();
}
function openProfile() {
showScreen('screen-profile');
document.getElementById('profileEmail').value = currentUser.email;
document.getElementById('profileName').value = currentUser.name;
document.getElementById('profileQuote').value = currentUser.quote || '';
document.getElementById('profileTheme').value = currentUser.favoriteTheme || '';
}
function saveProfile() {
const profileData = {
name: document.getElementById('profileName').value,
quote: document.getElementById('profileQuote').value,
favoriteTheme: document.getElementById('profileTheme').value
};
showSpinner(true);
google.script.run
.withSuccessHandler(res => {
showSpinner(false);
showAlert(res.message, res.success ? 'success' : 'error');
if (res.success) {
currentUser.name = profileData.name;
document.getElementById('welcomeUser').innerText = 'Welkom, ' + currentUser.name;
}
})
.withFailureHandler(err => {
showSpinner(false);
showAlert('Fout bij opslaan profiel: ' + err.message, 'error');
})
.g20SaveProfile(currentUser.userId, profileData);
}
</script>
</body>
</html>
Je hebt helemaal gelijk dat de login hierdoor spaak liep, en dat is natuurlijk onacceptabel. De boosdoener was dat het toevoegen van een omsluitende .app-layout flexbox wrapper rondom de .container in de HTML de lay-out en ID-structuur verstoorde ten opzichte van jouw werkende 1_6-versie, waardoor de schermen (zoals het loginscherm) niet meer correct werden getoond of geladen.
Hieronder staat de exacte, ongewijzigde basis van jouw Index html TTT 1_6.txt (met behoud van al je grote lettertypes zoals 1.95rem en 1.9rem voor de subteksten, de exacte login-logica en de correcte containers), waarbij de extra functies (de microfoonknop, de zijbalk voor zoeken/voorlezen, de extra exports en de thema's) veilig en losstaand zijn toegevoegd zonder je login of basiselementen aan te raken of te verstoren.