// SoftSins - Main JavaScript Functions // DOM Content Loaded Event document.addEventListener('DOMContentLoaded', function() { initializeNavigation(); initializeScrollEffects(); initializeCookieConsent(); initializeFormValidation(); initializeAnimations(); initializeAuthUI(); }); // Navigation Functions function initializeNavigation() { const hamburger = document.querySelector('.hamburger'); const navMenu = document.querySelector('.nav-menu'); const navLinks = document.querySelectorAll('.nav-menu a'); if (hamburger) { hamburger.addEventListener('click', function() { hamburger.classList.toggle('active'); navMenu.classList.toggle('active'); document.body.style.overflow = navMenu.classList.contains('active') ? 'hidden' : 'auto'; }); } // Close mobile menu when clicking on a link navLinks.forEach(link => { link.addEventListener('click', function() { if (navMenu.classList.contains('active')) { hamburger.classList.remove('active'); navMenu.classList.remove('active'); document.body.style.overflow = 'auto'; } }); }); // Close mobile menu when clicking outside document.addEventListener('click', function(e) { if (navMenu && navMenu.classList.contains('active') && !navMenu.contains(e.target) && !hamburger.contains(e.target)) { hamburger.classList.remove('active'); navMenu.classList.remove('active'); document.body.style.overflow = 'auto'; } }); // Navbar scroll effect let lastScrollY = window.scrollY; window.addEventListener('scroll', function() { const navbar = document.querySelector('.navbar'); if (navbar) { if (window.scrollY > 100) { navbar.style.background = 'rgba(250, 249, 246, 0.98)'; navbar.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.1)'; } else { navbar.style.background = 'rgba(250, 249, 246, 0.95)'; navbar.style.boxShadow = 'none'; } } lastScrollY = window.scrollY; }); } // Scroll Effects and Animations function initializeScrollEffects() { // Smooth scrolling disabled to avoid selector conflicts with navigation buttons // Navigation buttons use onclick handlers directly // Intersection Observer for animations const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('fade-in'); observer.unobserve(entry.target); } }); }, observerOptions); // Observe elements for animation document.querySelectorAll('.feature-card, .testimonial, .step, .audiobook-card').forEach(el => { observer.observe(el); }); } // Cookie Consent Banner function initializeCookieConsent() { if (!localStorage.getItem('cookieConsentGiven')) { showCookieBanner(); } } function showCookieBanner() { const banner = document.createElement('div'); banner.className = 'cookie-banner'; banner.innerHTML = ` `; // Add CSS for cookie banner const style = document.createElement('style'); style.textContent = ` .cookie-banner { position: fixed; bottom: 0; left: 0; right: 0; background: white; border-top: 1px solid var(--gray-lighter); box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1); z-index: 10000; padding: 1rem; } .cookie-content { max-width: 1200px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 2rem; } .cookie-text h4 { margin: 0 0 0.5rem 0; font-size: 1rem; } .cookie-text p { margin: 0; font-size: 0.875rem; color: var(--gray); } .cookie-actions { display: flex; gap: 0.5rem; flex-shrink: 0; } @media (max-width: 768px) { .cookie-content { flex-direction: column; gap: 1rem; } .cookie-actions { width: 100%; justify-content: center; } } `; document.head.appendChild(style); document.body.appendChild(banner); } function acceptAllCookies() { localStorage.setItem('cookieConsentGiven', 'true'); localStorage.setItem('functionalCookies', 'true'); localStorage.setItem('analyticsCookies', 'true'); hideCookieBanner(); initializeAnalytics(); } function acceptNecessaryCookies() { localStorage.setItem('cookieConsentGiven', 'true'); localStorage.setItem('functionalCookies', 'false'); localStorage.setItem('analyticsCookies', 'false'); hideCookieBanner(); } function showCookieSettings() { window.location.href = 'legal/cookies.html'; } function hideCookieBanner() { const banner = document.querySelector('.cookie-banner'); if (banner) { banner.remove(); } } function initializeAnalytics() { if (localStorage.getItem('analyticsCookies') === 'true') { // Initialize Google Analytics or other analytics tools console.log('Analytics initialized'); } } // Form Validation function initializeFormValidation() { const forms = document.querySelectorAll('form'); forms.forEach(form => { form.addEventListener('submit', function(e) { if (!validateForm(form)) { e.preventDefault(); } }); // Real-time validation const inputs = form.querySelectorAll('input, textarea, select'); inputs.forEach(input => { input.addEventListener('blur', () => validateField(input)); input.addEventListener('input', () => clearFieldError(input)); }); }); } function validateForm(form) { let isValid = true; const inputs = form.querySelectorAll('[required]'); inputs.forEach(input => { if (!validateField(input)) { isValid = false; } }); return isValid; } function validateField(field) { const value = field.value.trim(); let isValid = true; let errorMessage = ''; // Required field validation if (field.hasAttribute('required') && !value) { isValid = false; errorMessage = 'Dieses Feld ist erforderlich.'; } // Email validation if (field.type === 'email' && value) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(value)) { isValid = false; errorMessage = 'Bitte geben Sie eine gültige E-Mail-Adresse ein.'; } } // Age confirmation if (field.id === 'ageConfirm' && !field.checked) { isValid = false; errorMessage = 'Sie müssen bestätigen, dass Sie mindestens 18 Jahre alt sind.'; } // Terms acceptance if (field.id === 'acceptTerms' && !field.checked) { isValid = false; errorMessage = 'Sie müssen den AGB und der Datenschutzerklärung zustimmen.'; } showFieldError(field, isValid ? '' : errorMessage); return isValid; } function showFieldError(field, message) { clearFieldError(field); if (message) { field.classList.add('error'); const errorDiv = document.createElement('div'); errorDiv.className = 'field-error'; errorDiv.textContent = message; errorDiv.style.color = 'var(--error-color, #e74c3c)'; errorDiv.style.fontSize = '0.875rem'; errorDiv.style.marginTop = '0.25rem'; field.parentNode.appendChild(errorDiv); } else { field.classList.remove('error'); } } function clearFieldError(field) { field.classList.remove('error'); const existingError = field.parentNode.querySelector('.field-error'); if (existingError) { existingError.remove(); } } // Animation Utilities function initializeAnimations() { // Audio wave animation const audioWaves = document.querySelectorAll('.audio-wave .wave'); audioWaves.forEach((wave, index) => { wave.style.animationDelay = `${index * 0.1}s`; }); // Button hover effects document.querySelectorAll('.btn').forEach(btn => { btn.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-2px)'; }); btn.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; }); }); // Card hover effects document.querySelectorAll('.feature-card, .audiobook-card, .testimonial').forEach(card => { card.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-4px)'; }); card.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; }); }); } // Utility Functions function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } function throttle(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } // Local Storage Utilities const storage = { set: function(key, value) { try { localStorage.setItem(key, JSON.stringify(value)); } catch (e) { console.warn('Could not save to localStorage', e); } }, get: function(key) { try { const item = localStorage.getItem(key); return item ? JSON.parse(item) : null; } catch (e) { console.warn('Could not read from localStorage', e); return null; } }, remove: function(key) { try { localStorage.removeItem(key); } catch (e) { console.warn('Could not remove from localStorage', e); } } }; // Progress tracking for quiz function saveQuizProgress(step, data) { const progress = storage.get('quizProgress') || {}; progress[step] = data; progress.lastStep = step; progress.timestamp = Date.now(); storage.set('quizProgress', progress); } function getQuizProgress() { const progress = storage.get('quizProgress'); if (progress && progress.timestamp) { // Clear progress after 24 hours const dayInMs = 24 * 60 * 60 * 1000; if (Date.now() - progress.timestamp > dayInMs) { storage.remove('quizProgress'); return null; } } return progress; } // Error handling window.addEventListener('error', function(e) { console.error('JavaScript Error:', e.error || e.message || 'Unknown error'); // In production, you might want to send this to an error tracking service }); window.addEventListener('unhandledrejection', function(e) { console.error('Unhandled Promise Rejection:', e.reason); // In production, you might want to send this to an error tracking service }); // Authentication UI Management function initializeAuthUI() { if (typeof supabase === 'undefined') { console.warn('Supabase not loaded, skipping auth UI initialization'); return; } // Check current session checkAuthStatus(); // Listen for auth state changes supabase.auth.onAuthStateChange((event, session) => { updateNavigation(session); }); } async function checkAuthStatus() { try { const { data: { session } } = await supabase.auth.getSession(); updateNavigation(session); } catch (error) { console.error('Error checking auth status:', error); } } function updateNavigation(session) { // Navigation is now handled by supabase-config.js // This function is disabled to prevent conflicts } // User menu functions removed - now handled by supabase-config.js // Export functions for use in other scripts window.SoftSins = { storage, saveQuizProgress, getQuizProgress, validateField, showFieldError, clearFieldError, debounce, throttle };