// Supabase configuration - REPLACE WITH YOUR ACTUAL SUPABASE CREDENTIALS const SUPABASE_URL = 'https://adcawzmrwxjccepmhqla.supabase.co'; const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFkY2F3em1yd3hqY2NlcG1ocWxhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjAwMzU4MzQsImV4cCI6MjA3NTYxMTgzNH0.nI1kA1awpbsySZe4Taxvjn1m9YiRO7WBayj0lcAmHpE'; // Initialize Supabase client (will be null until credentials are provided) let supabase = null; // Check if Supabase credentials are provided if (SUPABASE_URL !== 'YOUR_SUPABASE_URL_HERE' && SUPABASE_ANON_KEY !== 'YOUR_SUPABASE_ANON_KEY_HERE') { supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY); } // App state let currentUser = null; let currentScreen = 'welcome'; let isLoggedIn = false; let quizzes = []; let marketplaceQuizzes = []; let currentTheme = 'light'; let lastSelectedFile = null; // DOM elements const screens = { welcome: document.getElementById('welcomeScreen'), home: document.getElementById('homeScreen'), quizzes: document.getElementById('quizzesScreen'), marketplace: document.getElementById('marketplaceScreen'), profile: document.getElementById('profileScreen') }; // Initialize app document.addEventListener('DOMContentLoaded', function() { initializeApp(); setupEventListeners(); loadData(); loadTheme(); loadQuizSettings(); updateProfileSettings(); }); function initializeApp() { // Check external libraries console.log('🔍 KönyvtĂĄrak ellenƑrzĂ©se:'); console.log('- Mammoth.js:', typeof mammoth !== 'undefined' ? '✅ Betöltve' : '❌ HiĂĄnyzik'); console.log('- XLSX (SheetJS):', typeof XLSX !== 'undefined' ? '✅ Betöltve' : '❌ HiĂĄnyzik'); console.log('- Supabase:', typeof supabase !== 'undefined' && supabase ? '✅ BeĂĄllĂ­tva' : '❌ Nincs beĂĄllĂ­tva'); // Show library status if (typeof mammoth === 'undefined' || typeof XLSX === 'undefined') { showNotification('⚠ KĂŒlsƑ könyvtĂĄrak betöltĂ©se... EllenƑrizd az internet kapcsolatot!', 'warning'); // Retry loading libraries after a delay setTimeout(() => { if (typeof mammoth === 'undefined' || typeof XLSX === 'undefined') { showNotification('❌ KönyvtĂĄrak betöltĂ©se sikertelen! FrissĂ­tsd az oldalt.', 'error'); console.error('HiĂĄnyzĂł könyvtĂĄrak:', { mammoth: typeof mammoth !== 'undefined', XLSX: typeof XLSX !== 'undefined' }); } else { showNotification('✅ KönyvtĂĄrak sikeresen betöltve!', 'success'); } }, 3000); } else { showNotification('✅ Minden könyvtĂĄr elĂ©rhetƑ!', 'success'); } // Show Supabase setup message if credentials not provided if (!supabase) { console.log(` 🔧 SUPABASE BEÁLLÍTÁS SZÜKSÉGES: 1. Menj a https://supabase.com oldalra 2. Hozz lĂ©tre egy Ășj projektet 3. A Settings > API menĂŒben talĂĄlod: - Project URL - anon/public API key 4. CserĂ©ld ki a kĂłdban: - SUPABASE_URL = 'your-project-url' - SUPABASE_ANON_KEY = 'your-anon-key' 5. Hozd lĂ©tre ezeket a tĂĄblĂĄkat a SQL editorban: `); // Show SQL setup in console for easy copying console.log(` -- 📋 MÁSOLD BE EZT A SQL KÓDOT A SUPABASE SQL EDITORBA: -- Enable UUID extension CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- KvĂ­zek tĂĄbla CREATE TABLE public.quizzes ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, title TEXT NOT NULL, description TEXT, type TEXT NOT NULL, category TEXT, questions JSONB NOT NULL, user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Marketplace tĂĄbla CREATE TABLE public.marketplace_quizzes ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, quiz_id UUID REFERENCES public.quizzes(id) ON DELETE CASCADE, title TEXT NOT NULL, description TEXT NOT NULL, price_type TEXT NOT NULL CHECK (price_type IN ('free', 'paid', 'password')), price INTEGER DEFAULT 0, password TEXT, coupon_code TEXT, discount_type TEXT CHECK (discount_type IN ('percent', 'amount')), discount_value INTEGER DEFAULT 0, stripe_id TEXT, tags TEXT[] DEFAULT '{}', downloads INTEGER DEFAULT 0, user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- User kvĂ­zek tĂĄbla (letöltött marketplace kvĂ­zek) CREATE TABLE public.user_marketplace_quizzes ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, marketplace_quiz_id UUID REFERENCES public.marketplace_quizzes(id) ON DELETE CASCADE, quiz_data JSONB NOT NULL, purchased_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- KvĂ­z eredmĂ©nyek tĂĄbla CREATE TABLE public.quiz_results ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, quiz_id UUID REFERENCES public.quizzes(id) ON DELETE CASCADE, quiz_title TEXT NOT NULL, quiz_type TEXT NOT NULL, correct_answers INTEGER NOT NULL, total_questions INTEGER NOT NULL, percentage INTEGER NOT NULL, time_spent INTEGER DEFAULT 0, completed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- FelhasznĂĄlĂłi beĂĄllĂ­tĂĄsok tĂĄbla CREATE TABLE public.user_settings ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE UNIQUE, question_order TEXT DEFAULT 'original' CHECK (question_order IN ('original', 'random')), allow_skip BOOLEAN DEFAULT false, question_time_limit INTEGER DEFAULT 0, total_time_limit INTEGER DEFAULT 0, random_question_count INTEGER DEFAULT 0, notifications BOOLEAN DEFAULT false, sound_effects BOOLEAN DEFAULT false, theme TEXT DEFAULT 'light' CHECK (theme IN ('light', 'dark')), created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- FelhasznĂĄlĂłi eredmĂ©nyek tĂĄbla CREATE TABLE public.user_achievements ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, achievement_type TEXT NOT NULL, earned_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(user_id, achievement_type) ); -- Row Level Security (RLS) engedĂ©lyezĂ©se ALTER TABLE public.quizzes ENABLE ROW LEVEL SECURITY; ALTER TABLE public.marketplace_quizzes ENABLE ROW LEVEL SECURITY; ALTER TABLE public.user_marketplace_quizzes ENABLE ROW LEVEL SECURITY; ALTER TABLE public.quiz_results ENABLE ROW LEVEL SECURITY; ALTER TABLE public.user_settings ENABLE ROW LEVEL SECURITY; ALTER TABLE public.user_achievements ENABLE ROW LEVEL SECURITY; -- RLS Policies -- Quizzes policies CREATE POLICY "Users can view their own quizzes" ON public.quizzes FOR SELECT USING (auth.uid() = user_id); CREATE POLICY "Users can insert their own quizzes" ON public.quizzes FOR INSERT WITH CHECK (auth.uid() = user_id); CREATE POLICY "Users can update their own quizzes" ON public.quizzes FOR UPDATE USING (auth.uid() = user_id); CREATE POLICY "Users can delete their own quizzes" ON public.quizzes FOR DELETE USING (auth.uid() = user_id); -- Marketplace policies CREATE POLICY "Anyone can view marketplace quizzes" ON public.marketplace_quizzes FOR SELECT USING (true); CREATE POLICY "Users can insert their own marketplace quizzes" ON public.marketplace_quizzes FOR INSERT WITH CHECK (auth.uid() = user_id); CREATE POLICY "Users can update their own marketplace quizzes" ON public.marketplace_quizzes FOR UPDATE USING (auth.uid() = user_id); CREATE POLICY "Users can delete their own marketplace quizzes" ON public.marketplace_quizzes FOR DELETE USING (auth.uid() = user_id); -- User marketplace quizzes policies CREATE POLICY "Users can view their own marketplace quizzes" ON public.user_marketplace_quizzes FOR SELECT USING (auth.uid() = user_id); CREATE POLICY "Users can insert their own marketplace quizzes" ON public.user_marketplace_quizzes FOR INSERT WITH CHECK (auth.uid() = user_id); -- Quiz results policies CREATE POLICY "Users can view their own quiz results" ON public.quiz_results FOR SELECT USING (auth.uid() = user_id); CREATE POLICY "Users can insert their own quiz results" ON public.quiz_results FOR INSERT WITH CHECK (auth.uid() = user_id); -- User settings policies CREATE POLICY "Users can view their own settings" ON public.user_settings FOR SELECT USING (auth.uid() = user_id); CREATE POLICY "Users can insert their own settings" ON public.user_settings FOR INSERT WITH CHECK (auth.uid() = user_id); CREATE POLICY "Users can update their own settings" ON public.user_settings FOR UPDATE USING (auth.uid() = user_id); -- User achievements policies CREATE POLICY "Users can view their own achievements" ON public.user_achievements FOR SELECT USING (auth.uid() = user_id); CREATE POLICY "Users can insert their own achievements" ON public.user_achievements FOR INSERT WITH CHECK (auth.uid() = user_id); -- Indexes for better performance CREATE INDEX idx_quizzes_user_id ON public.quizzes(user_id); CREATE INDEX idx_quizzes_created_at ON public.quizzes(created_at); CREATE INDEX idx_marketplace_quizzes_created_at ON public.marketplace_quizzes(created_at); CREATE INDEX idx_marketplace_quizzes_price_type ON public.marketplace_quizzes(price_type); CREATE INDEX idx_quiz_results_user_id ON public.quiz_results(user_id); CREATE INDEX idx_quiz_results_completed_at ON public.quiz_results(completed_at); -- Functions for updating timestamps CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; -- Triggers for updating timestamps CREATE TRIGGER update_quizzes_updated_at BEFORE UPDATE ON public.quizzes FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_marketplace_quizzes_updated_at BEFORE UPDATE ON public.marketplace_quizzes FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_user_settings_updated_at BEFORE UPDATE ON public.user_settings FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ✅ SQL SETUP KÉSZ! Most add meg a Supabase URL-t Ă©s API kulcsot a kĂłdban. `); } } function loadTheme() { const savedTheme = localStorage.getItem('theme') || 'light'; currentTheme = savedTheme; document.documentElement.setAttribute('data-theme', savedTheme); updateThemeToggle(); } function toggleTheme() { currentTheme = currentTheme === 'dark' ? 'light' : 'dark'; document.documentElement.setAttribute('data-theme', currentTheme); localStorage.setItem('theme', currentTheme); updateThemeToggle(); } function updateThemeToggle() { const toggle = document.getElementById('themeToggle'); toggle.textContent = currentTheme === 'light' ? '🌙' : '☀'; } function setupEventListeners() { // Theme toggle document.getElementById('themeToggle').addEventListener('click', toggleTheme); // Welcome screen buttons document.getElementById('loginBtn').addEventListener('click', () => { document.getElementById('loginModal').classList.add('active'); }); document.getElementById('registerBtn').addEventListener('click', () => { document.getElementById('registerModal').classList.add('active'); }); document.getElementById('continueWithoutLogin').addEventListener('click', () => { continueWithoutLogin(); }); // Auto-start in offline mode if no login attempt setTimeout(() => { if (currentScreen === 'welcome' && !isLoggedIn) { continueWithoutLogin(); } }, 1000); // Navigation document.querySelectorAll('.nav-btn').forEach(btn => { btn.addEventListener('click', (e) => { const screen = e.currentTarget.dataset.screen; switchScreen(screen); }); }); // Create quiz button document.getElementById('createQuizBtn').addEventListener('click', () => { showCreateQuizModal(); }); // Close modals document.getElementById('closeCreateModal').addEventListener('click', () => { document.getElementById('createQuizModal').classList.remove('active'); }); document.getElementById('closeQuizForm').addEventListener('click', () => { document.getElementById('quizFormModal').classList.remove('active'); }); document.getElementById('closeLoginModal').addEventListener('click', () => { document.getElementById('loginModal').classList.remove('active'); }); document.getElementById('closeRegisterModal').addEventListener('click', () => { document.getElementById('registerModal').classList.remove('active'); }); document.getElementById('closeMarketplaceUpload').addEventListener('click', () => { document.getElementById('marketplaceUploadModal').classList.remove('active'); }); // Create quiz options document.querySelectorAll('.create-option').forEach(btn => { btn.addEventListener('click', (e) => { const type = e.currentTarget.dataset.type; showQuizForm(type); }); }); // Quiz form submission document.getElementById('quizDetailsForm').addEventListener('submit', handleQuizCreation); // Modal switching document.getElementById('showRegisterFromLogin').addEventListener('click', () => { document.getElementById('loginModal').classList.remove('active'); document.getElementById('registerModal').classList.add('active'); }); document.getElementById('showLoginFromRegister').addEventListener('click', () => { document.getElementById('registerModal').classList.remove('active'); document.getElementById('loginModal').classList.add('active'); }); // Form submissions document.getElementById('loginForm').addEventListener('submit', handleLogin); document.getElementById('registerForm').addEventListener('submit', handleRegister); // Marketplace buttons document.getElementById('browseMarketplaceBtn').addEventListener('click', () => { showBrowseMarketplace(); }); document.getElementById('uploadToMarketplaceBtn').addEventListener('click', () => { showUploadToMarketplace(); }); document.getElementById('backFromBrowse').addEventListener('click', () => { hideBrowseMarketplace(); }); document.getElementById('backFromUpload').addEventListener('click', () => { hideUploadToMarketplace(); }); function openLoginModalOnce(){const m=document.getElementById('loginModal'); if(!m.classList.contains('active')) m.classList.add('active');} const __lfu = document.getElementById('loginForUpload'); if (__lfu) __lfu.addEventListener('click', openLoginModalOnce); // Marketplace upload form document.getElementById('marketplaceUploadForm').addEventListener('submit', handleMarketplaceUpload); // --- Marketplace extra panels toggle & handlers --- const mpNewBtn = document.getElementById('mpUploadNewQuizBtn'); const mpExistingBtn = document.getElementById('mpUploadExistingQuizBtn'); const mpNewPanel = document.getElementById('mpUploadNewQuizPanel'); const mpExistingPanel = document.getElementById('mpUploadExistingPanel'); if (mpNewBtn && mpExistingBtn && mpNewPanel && mpExistingPanel) { mpNewBtn.addEventListener('click', () => { mpNewPanel.classList.toggle('hidden'); mpExistingPanel.classList.add('hidden'); }); mpExistingBtn.addEventListener('click', () => { mpExistingPanel.classList.toggle('hidden'); mpNewPanel.classList.add('hidden'); }); } // Toggle password input visibility for "new" panel const newPriceRadios = document.querySelectorAll('input[name="mpNewPriceType"]'); const mpNewPassword = document.getElementById('mpNewPassword'); newPriceRadios.forEach(r => { r.addEventListener('change', () => { if (r.value === 'password' && r.checked) { mpNewPassword.classList.remove('hidden'); } else if (r.value === 'free' && r.checked) { mpNewPassword.classList.add('hidden'); mpNewPassword.value = ''; } }); }); // Toggle password input visibility for "existing" panel const existPriceRadios = document.querySelectorAll('input[name="mpExistingPriceType"]'); const mpExistingPassword = document.getElementById('mpExistingPassword'); existPriceRadios.forEach(r => { r.addEventListener('change', () => { if (r.value === 'password' && r.checked) { mpExistingPassword.classList.remove('hidden'); } else if (r.value === 'free' && r.checked) { mpExistingPassword.classList.add('hidden'); mpExistingPassword.value = ''; } }); }); // File area for new upload panel (function setupMpFileArea(){ const area = document.querySelector('#mpUploadNewQuizPanel .file-upload-area'); const input = document.getElementById('mpFileInput'); if (!area || !input) return; area.addEventListener('click', () => input.click()); area.addEventListener('dragover', (e) => { e.preventDefault(); area.style.borderColor = 'var(--accent-primary)'; }); area.addEventListener('dragleave', (e) => { e.preventDefault(); area.style.borderColor = 'var(--border-color)'; }); area.addEventListener('drop', (e) => { e.preventDefault(); area.style.borderColor = 'var(--border-color)'; if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { input.files = e.dataTransfer.files; showNotification('FĂĄjl kivĂĄlasztva az Ășj piactĂ©r-feltöltĂ©shez.', 'success'); } }); })(); // Submit NEW quiz to marketplace (creates a quiz first, then publishes) const mpSubmitNewBtn = document.getElementById('mpSubmitNewQuiz'); if (mpSubmitNewBtn) { mpSubmitNewBtn.addEventListener('click', async () => { try { if (!isLoggedIn || !currentUser || !supabase) { openLoginModalOnce(); return; } const fileInput = document.getElementById('mpFileInput'); const title = document.getElementById('mpNewTitle').value.trim(); const description = document.getElementById('mpNewDescription').value.trim(); const category = document.getElementById('mpNewCategory').value.trim(); const priceType = (document.querySelector('input[name="mpNewPriceType"]:checked')?.value) || 'free'; const password = priceType === 'password' ? document.getElementById('mpNewPassword').value.trim() : null; if (!fileInput || !fileInput.files || fileInput.files.length === 0) { showNotification('VĂĄlassz egy fĂĄjlt!', 'error'); return; } if (!title) { showNotification('Adj cĂ­met a kvĂ­znek!', 'error'); return; } // Parse questions from file (keep simple: default to multiple-choice unless UI specifies otherwise) const questions = await processFileImport(fileInput.files[0], 'multiple-choice'); // Create quiz owned by current user const insertQuiz = { title, description, type: 'multiple-choice', category: category || null, questions, user_id: currentUser.id, created_at: new Date().toISOString() }; let { data: createdQuiz, error: quizErr } = await supabase .from('quizzes').insert([insertQuiz]).select().limit(1); if (quizErr) throw quizErr; const quizId = createdQuiz[0].id; // Publish to marketplace (free/password only for now) const insertMp = { quiz_id: quizId, title, description: description || '—', price_type: priceType, password: priceType === 'password' ? password : null, user_id: currentUser.id }; let { data: createdMp, error: mpErr } = await supabase .from('marketplace_quizzes').insert([insertMp]).select().limit(1); if (mpErr) throw mpErr; showNotification('KvĂ­z feltöltve a piactĂ©rre!', 'success'); // Reload marketplace lists if available try { loadMarketplaceData?.(); } catch(e) {} } catch (err) { console.error(err); showNotification('Hiba a piactĂ©rre feltöltĂ©s sorĂĄn.', 'error'); } }); } // Submit EXISTING quiz to marketplace const mpSubmitExistingBtn = document.getElementById('mpSubmitExistingQuiz'); if (mpSubmitExistingBtn) { mpSubmitExistingBtn.addEventListener('click', async () => { try { if (!isLoggedIn || !currentUser || !supabase) { openLoginModalOnce(); return; } const quizId = document.getElementById('mpExistingQuizSelect').value; const description = document.getElementById('mpExistingDescription').value.trim(); const priceType = (document.querySelector('input[name="mpExistingPriceType"]:checked')?.value) || 'free'; const password = priceType === 'password' ? document.getElementById('mpExistingPassword').value.trim() : null; if (!quizId) { showNotification('VĂĄlassz kvĂ­zt a listĂĄbĂłl!', 'error'); return; } let { data: quizRow, error: qErr } = await supabase.from('quizzes').select('*').eq('id', quizId).limit(1); if (qErr) throw qErr; if (!quizRow || quizRow.length === 0) { throw new Error('KivĂĄlasztott kvĂ­z nem talĂĄlhatĂł az adatbĂĄzisban.'); } const insertMp = { quiz_id: quizId, title: quizRow[0].title, description: (description || quizRow[0].description || '—'), price_type: priceType, password: priceType === 'password' ? password : null, user_id: currentUser.id }; let { data: createdMp, error: mpErr } = await supabase .from('marketplace_quizzes').insert([insertMp]).select().limit(1); if (mpErr) throw mpErr; showNotification('MeglĂ©vƑ kvĂ­z feltöltve a piactĂ©rre!', 'success'); try { loadMarketplaceData?.(); } catch(e) {} } catch (err) { console.error(err); showNotification('Hiba a piactĂ©rre feltöltĂ©s sorĂĄn.', 'error'); } }); } // Acquire from marketplace (delegated click; expects buttons with data-action="acquire" and data-id) const mpItems = document.getElementById('marketplaceItems'); if (mpItems) { mpItems.addEventListener('click', async (e) => { const t = e.target.closest('[data-action="acquire"]'); if (!t) return; const id = t.getAttribute('data-id'); if (!id) return; if (!isLoggedIn || !currentUser || !supabase) { openLoginModalOnce(); return; } try { await attemptAcquireMarketplaceQuiz(id); } catch (err) { console.error(err); showNotification('Sikertelen beszerzĂ©s.', 'error'); } }); } // Price type change document.getElementById('priceType').addEventListener('change', (e) => { const priceSettings = document.getElementById('priceSettings'); const passwordSettings = document.getElementById('passwordSettings'); if (e.target.value === 'paid') { priceSettings.classList.remove('hidden'); passwordSettings.classList.add('hidden'); } else if (e.target.value === 'password') { passwordSettings.classList.remove('hidden'); priceSettings.classList.add('hidden'); } else { priceSettings.classList.add('hidden'); passwordSettings.classList.add('hidden'); } }); // Tab switching document.querySelectorAll('.tab-button').forEach(btn => { btn.addEventListener('click', (e) => { const tabName = e.currentTarget.dataset.tab; switchTab(tabName); }); }); // Search marketplace const searchInput = document.getElementById('searchMarketplace'); if (searchInput) { searchInput.addEventListener('input', (e) => { filterMarketplace(e.target.value); }); } // File upload handling setupFileUploadListeners(); } function setupFileUploadListeners() { // This will be called when the modal is shown setTimeout(() => { const fileUploadArea = document.querySelector('.file-upload-area'); const fileInput = document.getElementById('fileInput'); if (fileUploadArea && fileInput) { // Remove existing listeners to prevent duplicates fileUploadArea.replaceWith(fileUploadArea.cloneNode(true)); const newFileUploadArea = document.querySelector('.file-upload-area'); const newFileInput = document.getElementById('fileInput'); newFileUploadArea.addEventListener('click', () => { newFileInput.click(); }); newFileUploadArea.addEventListener('dragover', (e) => { e.preventDefault(); newFileUploadArea.style.borderColor = 'var(--accent-primary)'; }); newFileUploadArea.addEventListener('dragleave', (e) => { e.preventDefault(); newFileUploadArea.style.borderColor = 'var(--border-color)'; }); newFileUploadArea.addEventListener('drop', (e) => { e.preventDefault(); newFileUploadArea.style.borderColor = 'var(--border-color)'; const files = e.dataTransfer.files; if (files.length > 0) { const dt = new DataTransfer(); for (let i = 0; i < files.length; i++) dt.items.add(files[i]); newFileInput.files = dt.files; lastSelectedFile = files[0]; handleFileUpload(files[0]); } }); newFileInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { lastSelectedFile = e.target.files[0]; handleFileUpload(e.target.files[0]); } }); } }, 100); } // === SHOW UPLOAD TO MARKETPLACE MODAL === function showUploadToMarketplace() { const modal = document.getElementById('marketplaceUploadModal'); if (!modal) { console.warn('[showUploadToMarketplace] #marketplaceUploadModal nem talĂĄlhatĂł a DOM-ban.'); return; } // 1) Modal megnyitĂĄsa modal.classList.add('active'); // 2) Panelek alaphelyzet const mpNewPanel = document.getElementById('mpUploadNewQuizPanel'); const mpExistingPanel = document.getElementById('mpUploadExistingQuizPanel'); mpNewPanel?.classList.add('hidden'); mpExistingPanel?.classList.add('hidden'); // 3) MezƑk alaphelyzet (Ʊrlapok kiĂŒrĂ­tĂ©se) [ 'mpNewTitle', 'mpNewDescription', 'mpNewCategory', 'mpNewPassword', 'mpExistingDescription', 'mpExistingPassword' ].forEach(id => { const el = document.getElementById(id); if (el) el.value = ''; }); // Árak/jelszavas opciĂł alaphelyzet const newPriceFree = document.querySelector('input[name="mpNewPriceType"][value="free"]'); const existingPriceFree = document.querySelector('input[name="mpExistingPriceType"][value="free"]'); if (newPriceFree) newPriceFree.checked = true; if (existingPriceFree) existingPriceFree.checked = true; document.getElementById('mpNewPassword')?.classList.add('hidden'); document.getElementById('mpExistingPassword')?.classList.add('hidden'); // 4) MeglĂ©vƑ kvĂ­zek legördĂŒlƑ feltöltĂ©se const select = document.getElementById('mpExistingQuizSelect'); if (select) { const source = (Array.isArray(quizzes) && quizzes.length) ? quizzes : JSON.parse(localStorage.getItem('localQuizzes') || '[]'); select.innerHTML = ''; source.forEach(q => { if (!q) return; const opt = document.createElement('option'); opt.value = q.id || ''; opt.textContent = q.title || 'NĂ©vtelen kvĂ­z'; select.appendChild(opt); }); } // 5) FĂĄjlfeltöltƑ esemĂ©nyek ĂșjrahuzalozĂĄsa (ha kell) try { setupFileUploadListeners?.(); } catch (e) { console.debug('setupFileUploadListeners skip:', e); } // 6) UX: fĂłkusz a "Új kvĂ­z" panel gombra document.getElementById('mpUploadNewQuizBtn')?.focus(); } function handleFileUpload(file) { const fileName = file.name.toLowerCase(); const fileSize = (file.size / 1024 / 1024).toFixed(2); // MB console.log('FĂĄjl feltöltĂ©s:', fileName, 'MĂ©ret:', fileSize, 'MB'); // Validate file type - Word, Excel Ă©s TXT fĂĄjlok if (!fileName.endsWith('.docx') && !fileName.endsWith('.doc') && !fileName.endsWith('.xlsx') && !fileName.endsWith('.xls') && !fileName.endsWith('.txt')) { showNotification('Csak Word (.docx, .doc), Excel (.xlsx, .xls) Ă©s TXT fĂĄjlok tĂĄmogatottak!', 'error'); return; } // Check file size (max 10MB) if (file.size > 10 * 1024 * 1024) { showNotification('A fĂĄjl tĂșl nagy! Maximum 10MB megengedett.', 'error'); return; } showNotification(`FĂĄjl sikeresen kivĂĄlasztva: ${file.name} (${fileSize} MB)`, 'success'); // Update UI to show selected file const fileUploadArea = document.querySelector('.file-upload-area'); if (fileUploadArea) { const fileIcon = fileName.includes('.xlsx') || fileName.includes('.xls') ? '📊' : fileName.includes('.docx') || fileName.includes('.doc') ? '📄' : fileName.includes('.txt') ? '📝' : '📁'; fileUploadArea.innerHTML = `
${fileIcon}
${file.name}
${fileSize} MB
✅ FĂĄjl kivĂĄlasztva - kattints a "KvĂ­z lĂ©trehozĂĄsa" gombra
`; } } function continueWithoutLogin() { isLoggedIn = false; currentUser = null; showMainApp(); showNotification('Helyi mĂłdban folytatod - csak helyi mentĂ©s Ă©rhetƑ el', 'info'); } function showMainApp() { // Hide welcome screen document.getElementById('welcomeScreen').classList.add('hidden'); // Show home screen document.getElementById('homeScreen').classList.remove('hidden'); // Show bottom navigation document.getElementById('bottomNav').classList.remove('hidden'); // Show floating action button document.getElementById('createQuizBtn').classList.remove('hidden'); // Update header updateHeaderActions(); currentScreen = 'home'; loadData(); } function updateHeaderActions() { const headerActions = document.getElementById('headerActions'); const themeToggle = document.getElementById('themeToggle'); if (isLoggedIn && currentUser) { headerActions.innerHTML = `
👋 ${currentUser.email}
`; document.getElementById('logoutBtn').addEventListener('click', handleLogout); document.getElementById('themeToggle').addEventListener('click', toggleTheme); } else { headerActions.innerHTML = `
đŸ“± Helyi mĂłd
`; document.getElementById('headerLoginBtn').addEventListener('click', openLoginModalOnce); document.getElementById('themeToggle').addEventListener('click', toggleTheme); } } function switchScreen(screenName) { // Hide all screens except welcome Object.values(screens).forEach(screen => { if (screen && screen.id !== 'welcomeScreen') { screen.classList.add('hidden'); } }); // Show selected screen if (screens[screenName]) { screens[screenName].classList.remove('hidden'); } // Update navigation document.querySelectorAll('.nav-btn').forEach(btn => { btn.classList.remove('nav-active'); btn.classList.add('opacity-60'); }); const activeBtn = document.querySelector(`[data-screen="${screenName}"]`); if (activeBtn) { activeBtn.classList.add('nav-active'); activeBtn.classList.remove('opacity-60'); } currentScreen = screenName; // Load screen-specific data if (screenName === 'marketplace') { if (!isLoggedIn) { showNotification('A piactĂ©r csak bejelentkezve Ă©rhetƑ el.', 'info'); openLoginModalOnce?.(); return; // ne jelenjen meg a piactĂ©r kijelentkezve } loadMarketplaceData(); } } function showCreateQuizModal() { document.getElementById('createQuizModal').classList.add('active'); } function switchTab(tabName) { // Update tab buttons document.querySelectorAll('.tab-button').forEach(btn => { btn.classList.remove('tab-active'); }); document.querySelector(`[data-tab="${tabName}"]`).classList.add('tab-active'); // Show/hide tab content document.querySelectorAll('.tab-content').forEach(content => { content.classList.add('hidden'); }); document.getElementById(tabName).classList.remove('hidden'); } function showQuizForm(type) { document.getElementById('createQuizModal').classList.remove('active'); document.getElementById('quizFormModal').classList.add('active'); // Show/hide relevant sections based on type const fileSection = document.getElementById('fileUploadSection'); const textSection = document.getElementById('textImportSection'); if (type === 'file') { fileSection.classList.remove('hidden'); textSection.classList.add('hidden'); // Setup file upload listeners when file section is shown setupFileUploadListeners(); } else if (type === 'text') { textSection.classList.remove('hidden'); fileSection.classList.add('hidden'); } else { fileSection.classList.add('hidden'); textSection.classList.add('hidden'); } // Store creation type document.getElementById('quizDetailsForm').dataset.creationType = type; } async function handleQuizCreation(e) { e.preventDefault(); const quizTitle = document.getElementById('quizTitle').value.trim(); const quizType = document.getElementById('quizType').value; // Validate required fields if (!quizTitle) { showNotification('A kvĂ­z cĂ­me kötelezƑ!', 'error'); return; } if (!quizType) { showNotification('VĂĄlassz kvĂ­z tĂ­pust!', 'error'); return; } const quizData = { title: quizTitle, description: document.getElementById('quizDescription').value.trim(), type: quizType, category: document.getElementById('quizCategory').value, questions: [], // Will be populated based on creation type created_at: new Date().toISOString() }; const creationType = e.target.dataset.creationType; try { showNotification('KvĂ­z feldolgozĂĄsa...', 'info'); if (creationType === 'manual') { // For manual creation, create empty quiz quizData.questions = []; } else if (creationType === 'text') { const importText = document.getElementById('importText').value.trim(); if (!importText) { showNotification('Adj meg szöveget a feldolgozĂĄshoz!', 'error'); return; } quizData.questions = await processTextImport(importText, quizData.type); } else if (creationType === 'file') { const fileInput = document.getElementById('fileInput'); let file = null; if (fileInput && fileInput.files && fileInput.files.length > 0) { file = fileInput.files[0]; } else if (lastSelectedFile) { file = lastSelectedFile; } if (!file) { showNotification('VĂĄlassz ki egy fĂĄjlt!', 'error'); return; } quizData.questions = await processFileImport(file, quizData.type); } // Validate that we have questions (except for manual creation) if (creationType !== 'manual' && (!quizData.questions || quizData.questions.length === 0)) { showNotification('Nem sikerĂŒlt kĂ©rdĂ©seket feldolgozni!', 'error'); return; } // Generate unique ID quizData.id = 'quiz_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); // Save to Supabase if user is logged in, otherwise save locally if (currentUser && supabase) { try { const { data, error } = await supabase .from('quizzes') .insert([{ ...quizData, user_id: currentUser.id }]) .select(); if (error) throw error; quizData.id = data[0].id; showNotification('KvĂ­z mentve az adatbĂĄzisba!', 'success'); } catch (error) { console.error('Supabase save error, falling back to local storage:', error); // Fallback to local storage if Supabase fails const localQuizzes = JSON.parse(localStorage.getItem('localQuizzes') || '[]'); localQuizzes.push(quizData); localStorage.setItem('localQuizzes', JSON.stringify(localQuizzes)); showNotification('KvĂ­z helyben mentve (online mentĂ©s sikertelen)', 'warning'); } } else { // Save locally if not logged in const localQuizzes = JSON.parse(localStorage.getItem('localQuizzes') || '[]'); localQuizzes.push(quizData); localStorage.setItem('localQuizzes', JSON.stringify(localQuizzes)); showNotification('KvĂ­z helyben mentve!', 'success'); } // Add to current quizzes array quizzes.push(quizData); updateQuizzesList(); updateStats(); // Close modal and reset form document.getElementById('quizFormModal').classList.remove('active'); document.getElementById('quizDetailsForm').reset(); // Clear file input const fileInput = document.getElementById('fileInput'); if (fileInput) fileInput.value = ''; // Hide sections document.getElementById('fileUploadSection').classList.add('hidden'); document.getElementById('textImportSection').classList.add('hidden'); // Show success message with question count const questionCount = quizData.questions.length; if (questionCount > 0) { showNotification(`KvĂ­z lĂ©trehozva ${questionCount} kĂ©rdĂ©ssel! IndĂ­thatod a kvĂ­zt.`, 'success'); } else { showNotification('Üres kvĂ­z lĂ©trehozva! Adj hozzĂĄ kĂ©rdĂ©seket a szerkesztƑben.', 'success'); } // Switch to quizzes screen to show the new quiz switchScreen('quizzes'); } catch (error) { console.error('Error creating quiz:', error); showNotification('Hiba törtĂ©nt a kvĂ­z lĂ©trehozĂĄsakor: ' + (error.message || 'Ismeretlen hiba'), 'error'); } } async function processTextImport(text, quizType) { try { // Clean and normalize the text const cleanedText = text .replace(/\r\n/g, '\n') // Windows line endings .replace(/\r/g, '\n') // Mac line endings .replace(/\s+\n/g, '\n') // Remove trailing spaces .replace(/\n\s+/g, '\n') // Remove leading spaces .trim(); if (!cleanedText) { throw new Error('Üres szöveg!'); } const lines = cleanedText.split('\n').filter(line => line.trim()); if (lines.length === 0) { throw new Error('Nincsenek feldolgozhatĂł sorok!'); } // Use the selected quiz type (no auto-detection) if (!quizType || quizType === '') { throw new Error('VĂĄlassz kvĂ­z tĂ­pust!'); } let questions = []; if (quizType === 'multiple-choice') { questions = parseMultipleChoice(lines); } else if (quizType === 'multiple-answer') { questions = parseMultipleAnswer(lines); } else if (quizType === 'true-false') { questions = parseTrueFalse(lines); } else if (quizType === 'question-answer') { questions = parseQuestionAnswer(lines); } else if (quizType === 'word-card') { questions = parseWordCards(lines); } else if (quizType === 'concept-card') { questions = parseConceptCards(lines); } else { throw new Error('Ismeretlen kvĂ­z tĂ­pus: ' + quizType); } if (!questions || questions.length === 0) { throw new Error(`Nem sikerĂŒlt ${getQuizTypeLabel(quizType)} kĂ©rdĂ©seket felismerni a szövegbƑl. EllenƑrizd a formĂĄtumot!`); } console.log(`Feldolgozott kĂ©rdĂ©sek (${quizType}):`, questions); return questions; } catch (error) { console.error('Text processing error:', error); throw new Error('Szöveg feldolgozĂĄsi hiba: ' + error.message); } } function detectQuizType(lines) { const text = lines.join(' ').toLowerCase(); // Check for multiple choice patterns if (text.match(/[a-d]\)/g) && text.match(/helyes vĂĄlasz/i)) { return 'multiple-choice'; } // Check for true/false patterns if (text.match(/(igaz|hamis|true|false)/gi) && text.match(/helyes vĂĄlasz/i)) { return 'true-false'; } // Check for word cards (word - translation) if (text.match(/\s-\s/) || text.match(/\t/)) { const dashCount = (text.match(/\s-\s/g) || []).length; const tabCount = (text.match(/\t/g) || []).length; if (dashCount > 2 || tabCount > 2) { return 'word-card'; } } // Check for question-answer patterns if (text.match(/(kĂ©rdĂ©s|vĂĄlasz):/gi)) { return 'question-answer'; } // Check for concept cards (concept - definition) if (text.match(/\s-\s/) && lines.some(line => line.length > 50)) { return 'concept-card'; } // Default to question-answer if contains question marks if (text.match(/\?/g)) { return 'question-answer'; } // Default fallback return 'multiple-choice'; } function parseMultipleChoice(lines) { const questions = []; let currentQuestion = null; let currentOptions = []; let correctAnswer = ''; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); // Skip empty lines if (!line) continue; // Check if it's a correct answer line if (line.toLowerCase().match(/^(helyes vĂĄlasz|vĂĄlasz|correct answer):\s*/i)) { correctAnswer = line.replace(/^(helyes vĂĄlasz|vĂĄlasz|correct answer):\s*/i, '').trim(); if (currentQuestion && currentOptions.length > 0) { questions.push({ id: Date.now() + Math.random(), question: currentQuestion, options: currentOptions, correctAnswer: correctAnswer, type: 'multiple-choice' }); } // Reset for next question currentQuestion = null; currentOptions = []; correctAnswer = ''; continue; } // Check if it's an option (A), B), C), D) or a), b), c), d)) if (line.match(/^[A-Da-d][\)\.]?\s*/)) { currentOptions.push(line); continue; } // If we have options but no question yet, this might be the question if (currentOptions.length > 0 && !currentQuestion) { // This shouldn't happen in well-formatted text, skip continue; } // Otherwise, it's likely a new question if (!line.match(/^[A-Da-d][\)\.]?\s*/)) { // Save previous question if complete if (currentQuestion && currentOptions.length > 0 && correctAnswer) { questions.push({ id: Date.now() + Math.random(), question: currentQuestion, options: currentOptions, correctAnswer: correctAnswer, type: 'multiple-choice' }); } // Start new question currentQuestion = line.replace(/^\d+\.?\s*/, '').replace(/^kĂ©rdĂ©s:\s*/i, ''); currentOptions = []; correctAnswer = ''; } } // Handle last question if no explicit correct answer was found if (currentQuestion && currentOptions.length > 0) { // Try to find correct answer in the options themselves const correctOption = currentOptions.find(opt => opt.toLowerCase().includes('helyes') || opt.toLowerCase().includes('correct') ); if (correctOption) { correctAnswer = correctOption.charAt(0).toUpperCase(); } else { correctAnswer = 'A'; // Default to first option } questions.push({ id: Date.now() + Math.random(), question: currentQuestion, options: currentOptions, correctAnswer: correctAnswer, type: 'multiple-choice' }); } return questions; } function parseMultipleAnswer(lines) { const questions = []; let currentQuestion = null; let currentOptions = []; let correctAnswers = []; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line && !line.match(/^[A-D]\)/)) { if (line.toLowerCase().startsWith('helyes vĂĄlasz:')) { const answerText = line.replace(/helyes vĂĄlasz:\s*/i, '').trim(); // Parse multiple correct answers (A, C or A) Text, C) Text) if (answerText.includes(',')) { correctAnswers = answerText.split(',').map(a => a.trim()); } else { correctAnswers = [answerText]; } if (currentQuestion && currentOptions.length > 0) { questions.push({ id: Date.now() + Math.random(), question: currentQuestion, options: currentOptions, correctAnswers: correctAnswers, type: 'multiple-answer' }); } currentQuestion = null; currentOptions = []; correctAnswers = []; } else { currentQuestion = line.replace(/^\d+\.?\s*/, ''); currentOptions = []; } } else if (line.match(/^[A-D]\)/)) { currentOptions.push(line); } } return questions; } function parseTrueFalse(lines) { const questions = []; let currentStatement = null; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; // Check for explicit answer markers if (line.toLowerCase().match(/^(helyes vĂĄlasz|vĂĄlasz|answer):\s*/i)) { const answer = line.replace(/^(helyes vĂĄlasz|vĂĄlasz|answer):\s*/i, '').trim(); if (currentStatement) { const isTrue = answer.toLowerCase().match(/^(igaz|true|t|1)$/i); questions.push({ id: Date.now() + Math.random(), statement: currentStatement, correctAnswer: !!isTrue, type: 'true-false' }); } currentStatement = null; continue; } // Check if line is just true/false answer if (line.toLowerCase().match(/^(igaz|hamis|true|false|t|f)$/i)) { if (currentStatement) { const isTrue = line.toLowerCase().match(/^(igaz|true|t)$/i); questions.push({ id: Date.now() + Math.random(), statement: currentStatement, correctAnswer: !!isTrue, type: 'true-false' }); } currentStatement = null; continue; } // Check if statement ends with (Igaz) or (Hamis) const statementWithAnswer = line.match(/^(.+?)\s*\((igaz|hamis|true|false)\)$/i); if (statementWithAnswer) { const statement = statementWithAnswer[1].trim(); const answer = statementWithAnswer[2].toLowerCase(); const isTrue = answer.match(/^(igaz|true)$/i); questions.push({ id: Date.now() + Math.random(), statement: statement, correctAnswer: !!isTrue, type: 'true-false' }); continue; } // Otherwise, it's likely a statement if (!line.toLowerCase().includes('helyes vĂĄlasz')) { // Save previous statement if we have one without answer if (currentStatement) { // Default to true if no explicit answer questions.push({ id: Date.now() + Math.random(), statement: currentStatement, correctAnswer: true, type: 'true-false' }); } currentStatement = line.replace(/^\d+\.?\s*/, ''); } } // Handle last statement if (currentStatement) { questions.push({ id: Date.now() + Math.random(), statement: currentStatement, correctAnswer: true, // Default to true type: 'true-false' }); } return questions; } function parseQuestionAnswer(lines) { const questions = []; let currentQuestion = null; let currentAnswer = null; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; // Check for explicit question markers if (line.toLowerCase().match(/^(kĂ©rdĂ©s|question):\s*/i)) { currentQuestion = line.replace(/^(kĂ©rdĂ©s|question):\s*/i, '').trim(); continue; } // Check for explicit answer markers if (line.toLowerCase().match(/^(helyes vĂĄlasz|vĂĄlasz|answer):\s*/i)) { currentAnswer = line.replace(/^(helyes vĂĄlasz|vĂĄlasz|answer):\s*/i, '').trim(); if (currentQuestion && currentAnswer) { questions.push({ id: Date.now() + Math.random(), question: currentQuestion, answer: currentAnswer, type: 'question-answer' }); } currentQuestion = null; currentAnswer = null; continue; } // If line ends with question mark, it's likely a question if (line.endsWith('?')) { // Save previous Q&A if exists if (currentQuestion && currentAnswer) { questions.push({ id: Date.now() + Math.random(), question: currentQuestion, answer: currentAnswer, type: 'question-answer' }); } currentQuestion = line.replace(/^\d+\.?\s*/, ''); currentAnswer = null; continue; } // If we have a question but no answer yet, this might be the answer if (currentQuestion && !currentAnswer) { currentAnswer = line; questions.push({ id: Date.now() + Math.random(), question: currentQuestion, answer: currentAnswer, type: 'question-answer' }); currentQuestion = null; currentAnswer = null; continue; } // If no current question, this might be a question without question mark if (!currentQuestion) { currentQuestion = line.replace(/^\d+\.?\s*/, ''); } } // Handle last question if it exists if (currentQuestion && currentAnswer) { questions.push({ id: Date.now() + Math.random(), question: currentQuestion, answer: currentAnswer, type: 'question-answer' }); } return questions; } function parseWordCards(lines) { const questions = []; for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; let parts = []; // Try different separation methods in order of preference if (trimmed.includes('\t')) { parts = trimmed.split('\t'); } else if (trimmed.includes(' - ')) { parts = trimmed.split(' - '); } else if (trimmed.includes(' – ')) { parts = trimmed.split(' – '); } else if (trimmed.includes(' | ')) { parts = trimmed.split(' | '); } else if (trimmed.includes(': ')) { parts = trimmed.split(': '); } else if (trimmed.includes(' = ')) { parts = trimmed.split(' = '); } else { // Try simple dash, but be careful not to split compound words const dashIndex = trimmed.indexOf('-'); if (dashIndex > 0 && dashIndex < trimmed.length - 1) { // Make sure it's not part of a compound word const beforeDash = trimmed.charAt(dashIndex - 1); const afterDash = trimmed.charAt(dashIndex + 1); if (beforeDash === ' ' || afterDash === ' ') { parts = trimmed.split('-'); } } } // Clean up parts and validate if (parts.length >= 2) { const nativeWord = parts[0].trim().replace(/^\d+\.?\s*/, ''); const foreignWord = parts.slice(1).join(' - ').trim(); if (nativeWord && foreignWord && nativeWord.length > 0 && foreignWord.length > 0) { questions.push({ id: Date.now() + Math.random(), nativeWord: nativeWord, foreignWord: foreignWord, type: 'word-card' }); } } } return questions; } function parseConceptCards(lines) { const questions = []; for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; let parts = []; // Try different separation methods in order of preference if (trimmed.includes('\t')) { parts = trimmed.split('\t'); } else if (trimmed.includes(' - ')) { parts = trimmed.split(' - '); } else if (trimmed.includes(' – ')) { parts = trimmed.split(' – '); } else if (trimmed.includes(' | ')) { parts = trimmed.split(' | '); } else if (trimmed.includes(': ')) { parts = trimmed.split(': '); } else if (trimmed.includes(' = ')) { parts = trimmed.split(' = '); } else { // Try simple dash for concepts const dashIndex = trimmed.indexOf('-'); if (dashIndex > 0 && dashIndex < trimmed.length - 1) { const beforeDash = trimmed.charAt(dashIndex - 1); const afterDash = trimmed.charAt(dashIndex + 1); if (beforeDash === ' ' || afterDash === ' ') { parts = trimmed.split('-'); } } } // Clean up parts and validate if (parts.length >= 2) { const concept = parts[0].trim().replace(/^\d+\.?\s*/, ''); const definition = parts.slice(1).join(' - ').trim(); if (concept && definition && concept.length > 0 && definition.length > 0) { questions.push({ id: Date.now() + Math.random(), concept: concept, definition: definition, type: 'concept-card' }); } } } return questions; } async function processFileImport(file, quizType) { const fileName = file.name.toLowerCase(); try { if (fileName.endsWith('.docx') || fileName.endsWith('.doc')) { showNotification('Word fĂĄjl feldolgozĂĄsa...', 'info'); return await readWordFile(file, quizType); } else if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) { showNotification('Excel fĂĄjl feldolgozĂĄsa...', 'info'); return await readExcelFile(file, quizType); } else { throw new Error('Csak Word (.docx, .doc) Ă©s Excel (.xlsx, .xls) fĂĄjlok tĂĄmogatottak!'); } } catch (error) { console.error('File processing error:', error); showNotification('Hiba a fĂĄjl feldolgozĂĄsakor: ' + error.message, 'error'); return []; } } async function readWordFile(file, quizType) { try { console.log('Word fĂĄjl feldolgozĂĄs kezdĂ©se:', file.name); if (file.name.toLowerCase().endsWith('.docx')) { // Check if Mammoth.js is loaded if (typeof mammoth === 'undefined') { console.error('Mammoth könyvtĂĄr nem talĂĄlhatĂł!'); throw new Error('Mammoth könyvtĂĄr nem elĂ©rhetƑ! EllenƑrizd az internet kapcsolatot.'); } console.log('Mammoth könyvtĂĄr elĂ©rhetƑ, fĂĄjl olvasĂĄsa...'); const arrayBuffer = await file.arrayBuffer(); console.log('ArrayBuffer lĂ©trehozva, mĂ©ret:', arrayBuffer.byteLength); const result = await mammoth.extractRawText({arrayBuffer: arrayBuffer}); const text = result.value; console.log('Mammoth eredmĂ©ny:', { textLength: text ? text.length : 0, messages: result.messages, firstChars: text ? text.substring(0, 100) : 'nincs szöveg' }); if (!text || text.trim().length === 0) { throw new Error('Nem sikerĂŒlt szöveget kinyerni a Word fĂĄjlbĂłl! A fĂĄjl lehet, hogy ĂŒres vagy sĂ©rĂŒlt.'); } console.log('Word szöveg sikeresen kinyerve:', text.substring(0, 200) + '...'); return await processTextImport(text, quizType); } else { throw new Error('Jelenleg csak .docx fĂĄjlok tĂĄmogatottak (.doc nem)'); } } catch (error) { console.error('Word processing error:', error); throw new Error('Word fĂĄjl feldolgozĂĄsi hiba: ' + error.message); } } async function readExcelFile(file, quizType) { try { console.log('Excel fĂĄjl feldolgozĂĄs kezdĂ©se:', file.name); if (typeof XLSX === 'undefined') { console.error('XLSX könyvtĂĄr nem talĂĄlhatĂł!'); throw new Error('XLSX könyvtĂĄr nem elĂ©rhetƑ! EllenƑrizd az internet kapcsolatot.'); } console.log('XLSX könyvtĂĄr elĂ©rhetƑ, fĂĄjl olvasĂĄsa...'); // Use SheetJS to read Excel file const arrayBuffer = await file.arrayBuffer(); console.log('ArrayBuffer lĂ©trehozva, mĂ©ret:', arrayBuffer.byteLength); const workbook = XLSX.read(arrayBuffer, {type: 'array'}); console.log('Workbook betöltve, munkalapok:', workbook.SheetNames); // Get first worksheet const sheetName = workbook.SheetNames[0]; if (!sheetName) { throw new Error('Nem talĂĄlhatĂł munkalap a fĂĄjlban!'); } const worksheet = workbook.Sheets[sheetName]; // Convert to array of arrays const rows = XLSX.utils.sheet_to_json(worksheet, {header: 1}); console.log('Excel sorok beolvasva:', { totalRows: rows.length, firstRow: rows[0], secondRow: rows[1] }); if (!rows || rows.length === 0) { throw new Error('Nem sikerĂŒlt sorokat olvasni a fĂĄjlbĂłl! A fĂĄjl lehet, hogy ĂŒres.'); } if (rows.length < 2) { throw new Error('A fĂĄjlnak legalĂĄbb 2 sort kell tartalmaznia (fejlĂ©c + adatok)'); } console.log(`Excel feldolgozĂĄsa: ${rows.length} sor, tĂ­pus: ${quizType}`); console.log('ElsƑ nĂ©hĂĄny sor:', rows.slice(0, 3)); let questions = []; if (quizType === 'multiple-choice') { questions = parseExcelMultipleChoice(rows); } else if (quizType === 'multiple-answer') { questions = parseExcelMultipleAnswer(rows); } else if (quizType === 'true-false') { questions = parseExcelTrueFalse(rows); } else if (quizType === 'question-answer') { questions = parseExcelQuestionAnswer(rows); } else if (quizType === 'word-card') { questions = parseExcelWordCards(rows); } else if (quizType === 'concept-card') { questions = parseExcelConceptCards(rows); } else { throw new Error('Ismeretlen kvĂ­z tĂ­pus: ' + quizType); } if (!questions || questions.length === 0) { throw new Error(`Nem sikerĂŒlt ${getQuizTypeLabel(quizType)} kĂ©rdĂ©seket feldolgozni a fĂĄjlbĂłl! EllenƑrizd a fĂĄjl formĂĄtumĂĄt.`); } console.log(`Feldolgozott kĂ©rdĂ©sek (${questions.length} db):`, questions); return questions; } catch (error) { console.error('Excel processing error:', error); throw new Error('Excel fĂĄjl feldolgozĂĄsi hiba: ' + error.message); } } function parseCSVText(text) { try { const rows = []; const lines = text.split('\n'); for (const line of lines) { const trimmedLine = line.trim(); if (!trimmedLine) continue; // CSV parsing with multiple separators const cells = []; let currentCell = ''; let inQuotes = false; for (let i = 0; i < trimmedLine.length; i++) { const char = trimmedLine[i]; if (char === '"') { inQuotes = !inQuotes; } else if ((char === ',' || char === ';' || char === '\t') && !inQuotes) { cells.push(currentCell.trim()); currentCell = ''; } else { currentCell += char; } } cells.push(currentCell.trim()); // Clean cells const cleanCells = cells.map(cell => { return cell.replace(/^"(.*)"$/, '$1').trim(); }); if (cleanCells.some(cell => cell && cell.length > 0)) { rows.push(cleanCells); } } console.log(`CSV parsing: ${rows.length} sor`); return rows; } catch (error) { console.error('CSV parsing error:', error); throw new Error('CSV feldolgozĂĄsi hiba: ' + error.message); } } function detectExcelQuizType(rows) { if (rows.length < 2) return 'multiple-choice'; // Start from second row (skip header) const dataRows = rows.slice(1).filter(row => row && row.some(cell => cell && cell.toString().trim())); if (dataRows.length === 0) return 'multiple-choice'; // Check first few data rows to determine structure const sampleRows = dataRows.slice(0, Math.min(3, dataRows.length)); for (const row of sampleRows) { if (!row || row.length < 2) continue; // True/False detection: 2 columns, second column contains igaz/hamis if (row.length === 2) { const secondCol = (row[1] || '').toString().toLowerCase().trim(); if (secondCol.match(/^(igaz|hamis|true|false|i|h|t|f)$/)) { return 'true-false'; } } // Question-Answer detection: 2 columns, no true/false pattern if (row.length === 2) { const firstCol = (row[0] || '').toString().trim(); const secondCol = (row[1] || '').toString().trim(); // If first column ends with ?, it's likely question-answer if (firstCol.endsWith('?')) { return 'question-answer'; } // If second column is long, it's likely a concept card if (secondCol.length > 50) { return 'concept-card'; } else { return 'word-card'; } } // Multiple choice/answer detection: 3+ columns if (row.length >= 3) { const lastCol = (row[row.length - 1] || '').toString().trim().toUpperCase(); // Check if last column contains multiple answers (A,B or A,C,D) if (lastCol.match(/^[A-Z](,[A-Z])+$/)) { return 'multiple-answer'; } // Single letter answer suggests multiple choice if (lastCol.match(/^[A-Z]$/)) { return 'multiple-choice'; } return 'multiple-choice'; // Default for 3+ columns } } return 'multiple-choice'; // Default fallback } function parseExcelMultipleChoice(rows) { const questions = []; // Start from row 2 (index 1) to skip header for (let i = 1; i < rows.length; i++) { const row = rows[i]; if (!row || row.length < 3) continue; // Need at least question + 2 options + answer const question = (row[0] || '').toString().trim(); if (!question) continue; // Extract options (all columns except first and last) const options = []; for (let j = 1; j < row.length - 1; j++) { const option = (row[j] || '').toString().trim(); if (option) { // Add letter prefix if not present const letter = String.fromCharCode(65 + (j - 1)); // A, B, C, D... const formattedOption = option.startsWith(letter + ')') ? option : `${letter}) ${option}`; options.push(formattedOption); } } const correctAnswer = (row[row.length - 1] || '').toString().trim().toUpperCase(); if (options.length >= 2 && correctAnswer) { questions.push({ id: Date.now() + Math.random(), question: question, options: options, correctAnswer: correctAnswer, type: 'multiple-choice' }); } } return questions; } function parseExcelMultipleAnswer(rows) { const questions = []; // Start from row 2 (index 1) to skip header for (let i = 1; i < rows.length; i++) { const row = rows[i]; if (!row || row.length < 3) continue; const question = (row[0] || '').toString().trim(); if (!question) continue; // Extract options (all columns except first and last) const options = []; for (let j = 1; j < row.length - 1; j++) { const option = (row[j] || '').toString().trim(); if (option) { const letter = String.fromCharCode(65 + (j - 1)); const formattedOption = option.startsWith(letter + ')') ? option : `${letter}) ${option}`; options.push(formattedOption); } } const correctAnswersStr = (row[row.length - 1] || '').toString().trim().toUpperCase(); const correctAnswers = correctAnswersStr.split(',').map(ans => ans.trim()).filter(ans => ans); if (options.length >= 2 && correctAnswers.length > 0) { questions.push({ id: Date.now() + Math.random(), question: question, options: options, correctAnswers: correctAnswers, type: 'multiple-answer' }); } } return questions; } function parseExcelTrueFalse(rows) { const questions = []; // Start from row 2 (index 1) to skip header for (let i = 1; i < rows.length; i++) { const row = rows[i]; if (!row || row.length < 2) continue; const statement = (row[0] || '').toString().trim(); const answerStr = (row[1] || '').toString().toLowerCase().trim(); if (!statement || !answerStr) continue; // Parse true/false answer let correctAnswer = null; if (answerStr.match(/^(igaz|true|i|t|1|igen)$/)) { correctAnswer = true; } else if (answerStr.match(/^(hamis|false|h|f|0|nem)$/)) { correctAnswer = false; } if (correctAnswer !== null) { questions.push({ id: Date.now() + Math.random(), statement: statement, correctAnswer: correctAnswer, type: 'true-false' }); } } return questions; } function parseExcelQuestionAnswer(rows) { const questions = []; // Start from row 2 (index 1) to skip header for (let i = 1; i < rows.length; i++) { const row = rows[i]; if (!row || row.length < 2) continue; const question = (row[0] || '').toString().trim(); const answer = (row[1] || '').toString().trim(); if (question && answer) { questions.push({ id: Date.now() + Math.random(), question: question, answer: answer, type: 'question-answer' }); } } return questions; } function parseExcelWordCards(rows) { const questions = []; // Start from row 2 (index 1) to skip header for (let i = 1; i < rows.length; i++) { const row = rows[i]; if (!row || row.length < 2) continue; const nativeWord = (row[0] || '').toString().trim(); const foreignWord = (row[1] || '').toString().trim(); if (nativeWord && foreignWord) { questions.push({ id: Date.now() + Math.random(), nativeWord: nativeWord, foreignWord: foreignWord, type: 'word-card' }); } } return questions; } function parseExcelConceptCards(rows) { const questions = []; // Start from row 2 (index 1) to skip header for (let i = 1; i < rows.length; i++) { const row = rows[i]; if (!row || row.length < 2) continue; const concept = (row[0] || '').toString().trim(); const definition = (row[1] || '').toString().trim(); if (concept && definition) { questions.push({ id: Date.now() + Math.random(), concept: concept, definition: definition, type: 'concept-card' }); } } return questions; } function readFileAsText(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => resolve(e.target.result); reader.onerror = (e) => reject(e); reader.readAsText(file, 'UTF-8'); }); } async function handleLogin(e) { e.preventDefault(); if (!supabase) { showNotification('Supabase beĂĄllĂ­tĂĄs szĂŒksĂ©ges!', 'error'); return; } const email = document.getElementById('loginEmail').value; const password = document.getElementById('loginPassword').value; try { const { data, error } = await supabase.auth.signInWithPassword({ email: email, password: password }); if (error) throw error; currentUser = data.user; isLoggedIn = true; document.getElementById('loginModal').classList.remove('active'); showNotification('Sikeres bejelentkezĂ©s!', 'success'); // Show main app if coming from welcome screen if (currentScreen === 'welcome') { showMainApp(); } else { updateHeaderActions(); await loadUserQuizzes(); } } catch (error) { console.error('Login error:', error); showNotification('BejelentkezĂ©si hiba: ' + error.message, 'error'); } } async function handleRegister(e) { e.preventDefault(); if (!supabase) { showNotification('Supabase beĂĄllĂ­tĂĄs szĂŒksĂ©ges!', 'error'); return; } const name = document.getElementById('registerName').value; const email = document.getElementById('registerEmail').value; const password = document.getElementById('registerPassword').value; const passwordConfirm = document.getElementById('registerPasswordConfirm').value; if (password !== passwordConfirm) { showNotification('A jelszavak nem egyeznek!', 'error'); return; } try { const { data, error } = await supabase.auth.signUp({ email: email, password: password, options: { data: { name: name } } }); if (error) throw error; document.getElementById('registerModal').classList.remove('active'); showNotification('RegisztrĂĄciĂł sikeres! EllenƑrizd az email-jeidet!', 'success'); // Clear form document.getElementById('registerForm').reset(); } catch (error) { console.error('Register error:', error); showNotification('RegisztrĂĄciĂłs hiba: ' + error.message, 'error'); } } async function handleLogout() { if (supabase) { await supabase.auth.signOut(); } currentUser = null; isLoggedIn = false; // Reset to welcome screen Object.values(screens).forEach(screen => { if (screen) screen.classList.add('hidden'); }); document.getElementById('welcomeScreen').classList.remove('hidden'); document.getElementById('bottomNav').classList.add('hidden'); document.getElementById('createQuizBtn').classList.add('hidden'); currentScreen = 'welcome'; quizzes = []; marketplaceQuizzes = []; showNotification('Sikeres kijelentkezĂ©s!', 'success'); } function updateStats() { const totalQuestions = quizzes.reduce((sum, quiz) => sum + (quiz.questions?.length || 0), 0); const results = JSON.parse(localStorage.getItem('quizResults') || '[]'); // Calculate played quizzes and average accuracy const playedQuizzes = results.length; const avgAccuracy = results.length > 0 ? Math.round(results.reduce((sum, result) => sum + result.percentage, 0) / results.length) : 0; document.getElementById('totalQuizzes').textContent = quizzes.length; document.getElementById('totalQuestions').textContent = totalQuestions; document.getElementById('playedQuizzes').textContent = playedQuizzes; document.getElementById('avgAccuracy').textContent = avgAccuracy + '%'; // Update recent activity const recentContainer = document.getElementById('recentActivity'); const recentQuizzes = quizzes.slice(0, 3); if (recentQuizzes.length === 0) { recentContainer.innerHTML = `
Még nincs tevékenység
`; } else { recentContainer.innerHTML = recentQuizzes.map(quiz => `
${quiz.title}
${getQuizTypeLabel(quiz.type)}
${new Date(quiz.created_at).toLocaleDateString('hu-HU')}
`).join(''); } } function showBrowseMarketplace() { document.getElementById('browseMarketplace').classList.remove('hidden'); loadMarketplaceItems(); } function hideBrowseMarketplace() { document.getElementById('browseMarketplace').classList.add('hidden'); } function hideUploadToMarketplace() { document.getElementById('uploadToMarketplace').classList.add('hidden'); } async function loadUserQuizzesForMarketplace() { const select = document.getElementById('selectQuizForMarketplace'); select.innerHTML = ''; quizzes.forEach(quiz => { const option = document.createElement('option'); option.value = quiz.id; option.textContent = quiz.title; select.appendChild(option); }); } async function handleMarketplaceUpload(e) { e.preventDefault(); if (!supabase || !currentUser) { showNotification('BejelentkezĂ©s szĂŒksĂ©ges!', 'error'); return; } const formData = { quiz_id: document.getElementById('selectQuizForMarketplace').value, description: document.getElementById('marketplaceDescription').value, price_type: document.getElementById('priceType').value, price: parseInt(document.getElementById('quizPrice').value) || 0, password: document.getElementById('quizPassword').value, coupon_code: document.getElementById('couponCode').value, discount_type: document.getElementById('discountType').value, discount_value: parseInt(document.getElementById('discountValue').value) || 0, stripe_id: document.getElementById('stripeId').value, tags: document.getElementById('marketplaceTags').value.split(',').map(tag => tag.trim()).filter(Boolean), category: (document.getElementById('marketplaceCustomCategory').value.trim() || document.getElementById('marketplaceCategory').value || null), target_audience: document.getElementById('marketplaceAudience').value, user_id: currentUser.id }; // Get quiz title for marketplace listing const selectedQuiz = quizzes.find(q => q.id === formData.quiz_id); if (!selectedQuiz) { showNotification('VĂĄlassz ki egy kvĂ­zt!', 'error'); return; } formData.title = selectedQuiz.title; try { const { data, error } = await supabase .from('marketplace_quizzes') .insert([formData]) .select(); if (error) throw error; showNotification('KvĂ­z sikeresen feltöltve a piactĂ©rre!', 'success'); document.getElementById('marketplaceUploadModal').classList.remove('active'); document.getElementById('marketplaceUploadForm').reset(); hideUploadToMarketplace(); } catch (error) { console.error('Marketplace upload error:', error); showNotification('Hiba törtĂ©nt a feltöltĂ©s sorĂĄn!', 'error'); } } async function loadMarketplaceItems() { const container = document.getElementById('marketplaceItems'); if (!supabase) { container.innerHTML = `
⚙

Supabase beĂĄllĂ­tĂĄs szĂŒksĂ©ges a piactĂ©r hasznĂĄlatĂĄhoz

`; return; } try { const { data, error } = await supabase .from('marketplace_quizzes') .select('*') .order('created_at', { ascending: false }); if (error) throw error; if (data.length === 0) { container.innerHTML = `
đŸ›ïž

Még nincsenek kvízek a piactéren

`; return; } container.innerHTML = data.map(item => `

${item.title}

${item.price_type === 'free' ? 'Ingyenes' : item.price_type === 'password' ? 'Jelszóval védett' : `${item.price} Ft` }

${item.description}

đŸ“„ ${item.downloads || 0} letöltĂ©s ${new Date(item.created_at).toLocaleDateString('hu-HU')}
${item.tags && item.tags.length > 0 ? `
${item.tags.map(tag => `${tag}`).join('')}
` : ''}
`).join(''); } catch (error) { console.error('Error loading marketplace items:', error); container.innerHTML = `
❌

Hiba történt a piactér betöltésekor

`; } } async function viewMarketplaceItem(itemId) { // This would show item details and purchase/download options showNotification('Kvíz részletek és våsårlås fejlesztés alatt!', 'info'); // For now, just add to user's marketplace quizzes if free if (supabase && currentUser) { try { const { data: item } = await supabase .from('marketplace_quizzes') .select('*') .eq('id', itemId) .single(); if (item && item.price_type === 'free') { // Add to user's marketplace quizzes const { error } = await supabase .from('user_marketplace_quizzes') .insert([{ user_id: currentUser.id, marketplace_quiz_id: itemId, quiz_data: { title: item.title, description: item.description } }]); if (!error) { // Update download count await supabase .from('marketplace_quizzes') .update({ downloads: (item.downloads || 0) + 1 }) .eq('id', itemId); showNotification('Ingyenes kvíz hozzåadva a kvízeidhez!', 'success'); loadUserMarketplaceQuizzes(); } } } catch (error) { console.error('Error downloading quiz:', error); } } } function filterMarketplace(searchTerm) { const items = document.querySelectorAll('.marketplace-item'); items.forEach(item => { const title = item.querySelector('h4').textContent.toLowerCase(); const description = item.querySelector('p').textContent.toLowerCase(); const matches = title.includes(searchTerm.toLowerCase()) || description.includes(searchTerm.toLowerCase()); item.style.display = matches ? 'block' : 'none'; }); } async function loadData() { await loadUserQuizzes(); await loadUserMarketplaceQuizzes(); updateStats(); } async function loadUserQuizzes() { if (supabase && currentUser) { try { const { data, error } = await supabase .from('quizzes') .select('*') .eq('user_id', currentUser.id) .order('created_at', { ascending: false }); if (error) throw error; quizzes = data || []; } catch (error) { console.error('Error loading user quizzes:', error); } } else { // Load from localStorage quizzes = JSON.parse(localStorage.getItem('localQuizzes') || '[]'); } updateQuizzesList(); } async function loadUserMarketplaceQuizzes() { if (supabase && currentUser) { try { const { data, error } = await supabase .from('user_marketplace_quizzes') .select('*') .eq('user_id', currentUser.id) .order('purchased_at', { ascending: false }); if (error) throw error; marketplaceQuizzes = data || []; } catch (error) { console.error('Error loading marketplace quizzes:', error); } } updateMarketplaceQuizzesList(); } async function loadMarketplaceData() { if (supabase) { try { const { data, error } = await supabase .from('marketplace_quizzes') .select('id') .limit(1); if (!error) { // Update marketplace count if needed } } catch (error) { console.error('Error loading marketplace data:', error); } } } function updateQuizzesList() { const container = document.getElementById('myQuizzesList'); if (quizzes.length === 0) { container.innerHTML = `
Még nincsenek kvízeid
`; return; } container.innerHTML = quizzes.map(quiz => `

${quiz.title}

${getQuizTypeLabel(quiz.type)}
${quiz.description ? `

${quiz.description}

` : ''}
${quiz.questions?.length || 0} kérdés
${new Date(quiz.created_at).toLocaleDateString('hu-HU')}
`).join(''); } function updateMarketplaceQuizzesList() { const container = document.getElementById('marketplaceQuizzesList'); if (marketplaceQuizzes.length === 0) { container.innerHTML = `
Még nincsenek marketplace kvízeid
`; return; } container.innerHTML = marketplaceQuizzes.map(quiz => `

${quiz.quiz_data.title}

${quiz.quiz_data.description}

Letöltve: ${new Date(quiz.purchased_at).toLocaleDateString('hu-HU')}
`).join(''); } function getQuizTypeLabel(type) { const labels = { 'multiple-choice': 'FeleletvĂĄlasztĂłs', 'multiple-answer': 'Több helyes', 'true-false': 'Igaz/Hamis', 'question-answer': 'KĂ©rdĂ©s-VĂĄlasz', 'concept-card': 'Fogalom kĂĄrtya', 'word-card': 'SzĂłkĂĄrtya' }; return labels[type] || type; } function showNotification(message, type = 'info') { // Create notification element const notification = document.createElement('div'); const bgColor = type === 'success' ? 'var(--success)' : type === 'error' ? 'var(--error)' : type === 'warning' ? 'var(--warning)' : 'var(--accent-primary)'; notification.className = 'fixed top-4 right-4 z-50 p-4 rounded-lg text-white max-w-sm'; notification.style.backgroundColor = bgColor; notification.textContent = message; document.body.appendChild(notification); // Remove after 3 seconds setTimeout(() => { notification.remove(); }, 3000); } // Quiz play functions function startQuiz(quizId) { const quiz = quizzes.find(q => q.id === quizId); if (!quiz) { showNotification('KvĂ­z nem talĂĄlhatĂł!', 'error'); return; } if (!quiz.questions || quiz.questions.length === 0) { showNotification('A kvĂ­zben nincsenek kĂ©rdĂ©sek!', 'error'); return; } // Store current quiz in sessionStorage for the play session sessionStorage.setItem('currentQuiz', JSON.stringify(quiz)); sessionStorage.setItem('currentQuestionIndex', '0'); sessionStorage.setItem('userAnswers', JSON.stringify([])); sessionStorage.setItem('score', '0'); // Show quiz play screen showQuizPlayScreen(quiz); } function editQuiz(quizId) { const quiz = quizzes.find(q => q.id === quizId); if (!quiz) { showNotification('KvĂ­z nem talĂĄlhatĂł!', 'error'); return; } // Store quiz for editing sessionStorage.setItem('editingQuiz', JSON.stringify(quiz)); showNotification('KvĂ­z szerkesztƑ fejlesztĂ©s alatt!', 'info'); } function showQuizPlayScreen(quiz) { // Hide main content but keep bottom nav document.getElementById('mainContent').classList.add('hidden'); document.getElementById('createQuizBtn').classList.add('hidden'); // Create quiz play container const playContainer = document.createElement('div'); playContainer.id = 'quizPlayContainer'; playContainer.className = 'quiz-play-container'; if (quiz.type === 'concept-card' || quiz.type === 'word-card') { playContainer.innerHTML = createFlashcardInterface(quiz); } else { playContainer.innerHTML = createQuizInterface(quiz); } document.querySelector('.app-container').appendChild(playContainer); // Initialize quiz play if (quiz.type === 'concept-card' || quiz.type === 'word-card') { initializeFlashcards(quiz); } else { initializeQuizPlay(quiz); } } function createQuizInterface(quiz) { const settings = JSON.parse(localStorage.getItem('quizSettings') || '{}'); return `

${quiz.title}

1 / ${quiz.questions.length}
${settings.totalTimeLimit > 0 ? '
⏱ --:--
' : ''}
0 pont
${settings.questionTimeLimit > 0 ? '
⏰ --s
' : ''}
${quiz.questions[0]?.question || quiz.questions[0]?.statement || 'Kérdés betöltése...'}
`; } function createFlashcardInterface(quiz) { return `

${quiz.title}

1 / ${quiz.questions.length}
0 / 0
KĂĄrtya
${quiz.questions[0]?.concept || quiz.questions[0]?.nativeWord || 'Betöltés...'}
`; } function initializeQuizPlay(quiz) { // Apply quiz settings const settings = JSON.parse(localStorage.getItem('quizSettings') || '{}'); // Apply question order setting if (settings.questionOrder === 'random') { quiz.questions = shuffleArray([...quiz.questions]); } // Apply random question count setting if (settings.randomQuestionCount > 0 && settings.randomQuestionCount < quiz.questions.length) { quiz.questions = quiz.questions.slice(0, settings.randomQuestionCount); } window.currentQuiz = quiz; window.currentQuestionIndex = 0; window.userAnswers = []; window.score = 0; window.quizSettings = settings; // Setup timers if enabled if (settings.totalTimeLimit > 0) { setupTotalTimer(settings.totalTimeLimit * 60); // Convert minutes to seconds } displayQuestion(0); } function shuffleArray(array) { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; } function setupTotalTimer(totalSeconds) { window.totalTimeRemaining = totalSeconds; window.totalTimerInterval = setInterval(() => { window.totalTimeRemaining--; updateTimerDisplay(); if (window.totalTimeRemaining <= 0) { clearInterval(window.totalTimerInterval); showNotification('⏰ IdƑ lejĂĄrt! KvĂ­z automatikusan befejezve.', 'warning'); showQuizResults(); } }, 1000); } function setupQuestionTimer(seconds) { if (window.questionTimerInterval) { clearInterval(window.questionTimerInterval); } window.questionTimeRemaining = seconds; window.questionTimerInterval = setInterval(() => { window.questionTimeRemaining--; updateQuestionTimerDisplay(); if (window.questionTimeRemaining <= 0) { clearInterval(window.questionTimerInterval); showNotification('⏰ KĂ©rdĂ©s ideje lejĂĄrt!', 'warning'); nextQuestion(); // Auto advance to next question } }, 1000); } function updateTimerDisplay() { const timerElement = document.getElementById('totalTimer'); if (timerElement && window.totalTimeRemaining !== undefined) { const minutes = Math.floor(window.totalTimeRemaining / 60); const seconds = window.totalTimeRemaining % 60; timerElement.textContent = `⏱ ${minutes}:${seconds.toString().padStart(2, '0')}`; } } function updateQuestionTimerDisplay() { const timerElement = document.getElementById('questionTimer'); if (timerElement && window.questionTimeRemaining !== undefined) { timerElement.textContent = `⏰ ${window.questionTimeRemaining}s`; // Change color when time is running out if (window.questionTimeRemaining <= 10) { timerElement.style.color = 'var(--error)'; } else if (window.questionTimeRemaining <= 30) { timerElement.style.color = 'var(--warning)'; } else { timerElement.style.color = 'var(--text-primary)'; } } } function initializeFlashcards(quiz) { window.currentQuiz = quiz; window.currentCardIndex = 0; window.knownCards = 0; window.totalCards = quiz.questions.length; window.isFlipped = false; displayCard(0); } function displayQuestion(index) { const quiz = window.currentQuiz; const question = quiz.questions[index]; const settings = window.quizSettings || {}; if (!question) return; // Clear any existing question timer if (window.questionTimerInterval) { clearInterval(window.questionTimerInterval); } // Update progress document.getElementById('questionProgress').textContent = `${index + 1} / ${quiz.questions.length}`; // Update question text const questionText = question.question || question.statement || 'KĂ©rdĂ©s'; document.getElementById('questionText').textContent = questionText; // Setup question timer if enabled if (settings.questionTimeLimit > 0) { setupQuestionTimer(settings.questionTimeLimit); } // Create answer options based on quiz type const optionsContainer = document.getElementById('answerOptions'); if (quiz.type === 'multiple-choice') { optionsContainer.innerHTML = question.options.map((option, i) => `
${option}
`).join('') + ` `; } else if (quiz.type === 'multiple-answer') { optionsContainer.innerHTML = question.options.map((option, i) => `
`).join('') + ` `; } else if (quiz.type === 'true-false') { optionsContainer.innerHTML = `
✅ Igaz
❌ Hamis
`; } else if (quiz.type === 'question-answer') { optionsContainer.innerHTML = ` `; } // Update navigation buttons document.getElementById('prevBtn').disabled = index === 0; document.getElementById('nextBtn').textContent = index === quiz.questions.length - 1 ? 'BefejezĂ©s' : 'KövetkezƑ'; } function displayCard(index) { const quiz = window.currentQuiz; const card = quiz.questions[index]; if (!card) return; // Update progress document.getElementById('cardProgress').textContent = `${index + 1} / ${quiz.questions.length}`; document.getElementById('cardScore').textContent = `${window.knownCards} / ${window.totalCards}`; // Show front of card const frontText = card.concept || card.nativeWord || 'KĂĄrtya'; const backText = card.definition || card.foreignWord || ''; document.getElementById('cardFront').textContent = frontText; document.getElementById('cardBack').textContent = backText; // Reset card state document.getElementById('cardFront').style.display = 'block'; document.getElementById('cardBack').style.display = 'none'; document.getElementById('flipBtn').style.display = 'block'; document.getElementById('cardControls').style.display = 'none'; window.isFlipped = false; // Update navigation buttons document.getElementById('prevCardBtn').disabled = index === 0; document.getElementById('nextCardBtn').textContent = index === quiz.questions.length - 1 ? 'BefejezĂ©s' : 'KövetkezƑ'; } function selectAnswer(answer) { // Remove previous selections document.querySelectorAll('.quiz-answer-option').forEach(opt => { opt.classList.remove('selected'); }); // Mark selected answer if (typeof answer === 'number') { document.querySelector(`[data-index="${answer}"]`).classList.add('selected'); } else { document.querySelector(`[data-answer="${answer}"]`).classList.add('selected'); } window.userAnswers[window.currentQuestionIndex] = answer; // Show check answer button const checkBtn = document.getElementById('checkAnswerBtn'); if (checkBtn) { checkBtn.style.display = 'block'; } } function toggleAnswer(index) { const option = document.querySelector(`[data-index="${index}"]`); const checkbox = option.querySelector('input[type="checkbox"]'); checkbox.checked = !checkbox.checked; option.classList.toggle('selected', checkbox.checked); // Store multiple answers if (!window.userAnswers[window.currentQuestionIndex]) { window.userAnswers[window.currentQuestionIndex] = []; } const answers = window.userAnswers[window.currentQuestionIndex]; if (checkbox.checked) { if (!answers.includes(index)) { answers.push(index); } } else { const answerIndex = answers.indexOf(index); if (answerIndex > -1) { answers.splice(answerIndex, 1); } } // Show check answer button if any answer is selected const checkBtn = document.getElementById('checkAnswerBtn'); if (checkBtn && answers.length > 0) { checkBtn.style.display = 'block'; } else if (checkBtn && answers.length === 0) { checkBtn.style.display = 'none'; } } function flipCard() { const front = document.getElementById('cardFront'); const back = document.getElementById('cardBack'); const flipBtn = document.getElementById('flipBtn'); const controls = document.getElementById('cardControls'); if (!window.isFlipped) { front.style.display = 'none'; back.style.display = 'block'; flipBtn.style.display = 'none'; controls.style.display = 'flex'; window.isFlipped = true; } } function markCard(known) { if (known) { window.knownCards++; } // Store result for detailed summary if (!window.cardResults) { window.cardResults = []; } window.cardResults[window.currentCardIndex] = known; // Move to next card window.currentCardIndex++; if (window.currentCardIndex >= window.currentQuiz.questions.length) { // Show flashcard results showFlashcardResults(); } else { displayCard(window.currentCardIndex); } } function previousCard() { if (window.currentCardIndex > 0) { window.currentCardIndex--; displayCard(window.currentCardIndex); } } function nextCard() { if (window.currentCardIndex < window.currentQuiz.questions.length - 1) { window.currentCardIndex++; displayCard(window.currentCardIndex); } else { showFlashcardResults(); } } function checkCurrentAnswer() { const quiz = window.currentQuiz; const question = quiz.questions[window.currentQuestionIndex]; const userAnswer = window.userAnswers[window.currentQuestionIndex]; if (!userAnswer && userAnswer !== false && userAnswer !== 0) { if (quiz.type === 'question-answer') { const answer = document.getElementById('answerInput').value.trim(); if (!answer) { showNotification('Adj meg egy vĂĄlaszt!', 'warning'); return; } window.userAnswers[window.currentQuestionIndex] = answer; } else { showNotification('VĂĄlassz egy opciĂłt!', 'warning'); return; } } let isCorrect = false; // Check answer based on quiz type if (quiz.type === 'multiple-choice') { const correctIndex = question.options.findIndex(opt => opt.startsWith(question.correctAnswer) || opt.includes(question.correctAnswer.replace(/[A-D]\)\s*/, '')) ); isCorrect = userAnswer === correctIndex; // Highlight correct/incorrect document.querySelectorAll('.quiz-answer-option').forEach((opt, i) => { if (i === correctIndex) { opt.classList.add('correct'); } else if (i === userAnswer) { opt.classList.add('incorrect'); } }); } else if (quiz.type === 'multiple-answer') { const correctIndices = question.correctAnswers.map(ans => { if (ans.match(/^[A-D]/)) { return question.options.findIndex(opt => opt.startsWith(ans)); } return question.options.findIndex(opt => opt.includes(ans)); }).filter(i => i !== -1); isCorrect = Array.isArray(userAnswer) && userAnswer.length === correctIndices.length && userAnswer.every(ans => correctIndices.includes(ans)); // Highlight correct/incorrect document.querySelectorAll('.quiz-answer-option').forEach((opt, i) => { if (correctIndices.includes(i)) { opt.classList.add('correct'); } else if (userAnswer && userAnswer.includes(i)) { opt.classList.add('incorrect'); } }); } else if (quiz.type === 'true-false') { isCorrect = userAnswer === question.correctAnswer; // Highlight correct/incorrect document.querySelectorAll('.quiz-answer-option').forEach(opt => { const optAnswer = opt.dataset.answer === 'true'; if (optAnswer === question.correctAnswer) { opt.classList.add('correct'); } else if (optAnswer === userAnswer) { opt.classList.add('incorrect'); } }); } else if (quiz.type === 'question-answer') { const answer = document.getElementById('answerInput').value.trim(); isCorrect = answer.toLowerCase().includes(question.answer.toLowerCase()); // Show correct answer const correctAnswerDiv = document.createElement('div'); correctAnswerDiv.className = `mt-2 p-2 rounded ${isCorrect ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`; correctAnswerDiv.innerHTML = `Helyes vĂĄlasz: ${question.answer}`; document.getElementById('answerInput').parentNode.appendChild(correctAnswerDiv); } // Hide check button and show result const checkBtn = document.getElementById('checkAnswerBtn'); if (checkBtn) { checkBtn.style.display = 'none'; } showNotification(isCorrect ? '✅ Helyes vĂĄlasz!' : '❌ Helytelen vĂĄlasz!', isCorrect ? 'success' : 'error'); } function nextQuestion() { const quiz = window.currentQuiz; const settings = window.quizSettings || {}; // Check if answer is required and not provided if (!settings.allowSkip) { const currentAnswer = window.userAnswers[window.currentQuestionIndex]; if (currentAnswer === undefined || currentAnswer === null || (Array.isArray(currentAnswer) && currentAnswer.length === 0)) { if (quiz.type === 'question-answer') { const answer = document.getElementById('answerInput').value.trim(); if (!answer) { showNotification('VĂĄlaszolj a kĂ©rdĂ©sre a tovĂĄbblĂ©pĂ©shez!', 'warning'); return; } window.userAnswers[window.currentQuestionIndex] = answer; } else { showNotification('VĂĄlassz egy opciĂłt a tovĂĄbblĂ©pĂ©shez!', 'warning'); return; } } } if (quiz.type === 'question-answer') { const answer = document.getElementById('answerInput').value.trim(); window.userAnswers[window.currentQuestionIndex] = answer; } // Clear question timer if (window.questionTimerInterval) { clearInterval(window.questionTimerInterval); } if (window.currentQuestionIndex >= quiz.questions.length - 1) { // Quiz finished showQuizResults(); } else { window.currentQuestionIndex++; displayQuestion(window.currentQuestionIndex); } } function previousQuestion() { if (window.currentQuestionIndex > 0) { window.currentQuestionIndex--; displayQuestion(window.currentQuestionIndex); } } function showQuizResults() { const quiz = window.currentQuiz; let correctAnswers = 0; let incorrectQuestions = []; // Clear all timers if (window.totalTimerInterval) { clearInterval(window.totalTimerInterval); } if (window.questionTimerInterval) { clearInterval(window.questionTimerInterval); } // Calculate score and track incorrect answers quiz.questions.forEach((question, index) => { const userAnswer = window.userAnswers[index]; let isCorrect = false; if (quiz.type === 'multiple-choice') { const correctIndex = question.options.findIndex(opt => opt.startsWith(question.correctAnswer) || opt.includes(question.correctAnswer.replace(/[A-D]\)\s*/, '')) ); isCorrect = userAnswer === correctIndex; } else if (quiz.type === 'multiple-answer') { const correctIndices = question.correctAnswers.map(ans => { if (ans.match(/^[A-D]/)) { return question.options.findIndex(opt => opt.startsWith(ans)); } return question.options.findIndex(opt => opt.includes(ans)); }).filter(i => i !== -1); isCorrect = Array.isArray(userAnswer) && userAnswer.length === correctIndices.length && userAnswer.every(ans => correctIndices.includes(ans)); } else if (quiz.type === 'true-false') { isCorrect = userAnswer === question.correctAnswer; } else if (quiz.type === 'question-answer') { isCorrect = userAnswer && userAnswer.toLowerCase().includes(question.answer.toLowerCase()); } if (isCorrect) { correctAnswers++; } else { incorrectQuestions.push(index); } }); const percentage = Math.round((correctAnswers / quiz.questions.length) * 100); // Check for achievements checkAchievements(percentage, correctAnswers, quiz.questions.length); // Save quiz result for statistics saveQuizResult(quiz, correctAnswers, quiz.questions.length, percentage); // Store incorrect questions for retry window.incorrectQuestions = incorrectQuestions; // Create detailed results const detailedResults = quiz.questions.map((question, index) => { const userAnswer = window.userAnswers[index]; const isCorrect = !incorrectQuestions.includes(index); return `
${isCorrect ? '✅' : '❌'} ${index + 1}. ${question.question || question.statement}
${quiz.type === 'multiple-choice' ? `Válaszod: ${userAnswer !== undefined ? question.options[userAnswer] || 'Nincs válasz' : 'Nincs válasz'}` : quiz.type === 'true-false' ? `Válaszod: ${userAnswer === true ? 'Igaz' : userAnswer === false ? 'Hamis' : 'Nincs válasz'}` : quiz.type === 'question-answer' ? `Válaszod: ${userAnswer || 'Nincs válasz'}` : 'Válasz ellenƑrizve' }
`; }).join(''); // Show results screen document.getElementById('quizPlayContainer').innerHTML = `

KvĂ­z befejezve!

${percentage >= 80 ? '🎉' : percentage >= 60 ? '👍' : '📚'}

${percentage}%

${correctAnswers} / ${quiz.questions.length} helyes vĂĄlasz

${correctAnswers}
Helyes
${incorrectQuestions.length}
HibĂĄs
${percentage}%
PontossĂĄg

Részletes eredmények:

${detailedResults}
${incorrectQuestions.length > 0 ? ` ` : ''}
`; } function showFlashcardResults() { const percentage = Math.round((window.knownCards / window.totalCards) * 100); const unknownCards = []; // Track unknown cards for retry if (window.cardResults) { window.cardResults.forEach((known, index) => { if (!known) { unknownCards.push(index); } }); } window.incorrectQuestions = unknownCards; // Create detailed results const detailedResults = window.currentQuiz.questions.map((card, index) => { const known = window.cardResults ? window.cardResults[index] : false; const frontText = card.concept || card.nativeWord || 'KĂĄrtya'; const backText = card.definition || card.foreignWord || ''; return `
${known ? '✅' : '❌'} ${frontText}
${backText}
`; }).join(''); document.getElementById('quizPlayContainer').innerHTML = `

KĂĄrtyĂĄk befejezve!

${percentage >= 80 ? '🎉' : percentage >= 60 ? '👍' : '📚'}

${percentage}%

${window.knownCards} / ${window.totalCards} kĂĄrtya tudtad

${window.knownCards}
Tudtam
${unknownCards.length}
Nem tudtam
${percentage}%
PontossĂĄg

Részletes eredmények:

${detailedResults}
${unknownCards.length > 0 ? ` ` : ''}
`; } function restartQuiz() { const quiz = JSON.parse(sessionStorage.getItem('currentQuiz')); if (quiz) { document.getElementById('quizPlayContainer').remove(); startQuiz(quiz.id); } } function retryIncorrectQuestions() { if (!window.incorrectQuestions || window.incorrectQuestions.length === 0) { showNotification('Nincsenek hibĂĄs vĂĄlaszok!', 'info'); return; } // Create a new quiz with only incorrect questions const originalQuiz = window.currentQuiz; const incorrectQuiz = { ...originalQuiz, questions: window.incorrectQuestions.map(index => originalQuiz.questions[index]), title: originalQuiz.title + ' - HibĂĄs vĂĄlaszok' }; // Store the incorrect quiz and restart sessionStorage.setItem('currentQuiz', JSON.stringify(incorrectQuiz)); sessionStorage.setItem('currentQuestionIndex', '0'); sessionStorage.setItem('userAnswers', JSON.stringify([])); sessionStorage.setItem('score', '0'); // Remove current play container and start new quiz document.getElementById('quizPlayContainer').remove(); showQuizPlayScreen(incorrectQuiz); } function exitQuiz() { // Clear all timers if (window.totalTimerInterval) { clearInterval(window.totalTimerInterval); } if (window.questionTimerInterval) { clearInterval(window.questionTimerInterval); } // Remove quiz play container const playContainer = document.getElementById('quizPlayContainer'); if (playContainer) { playContainer.remove(); } // Show main content again document.getElementById('mainContent').classList.remove('hidden'); document.getElementById('bottomNav').classList.remove('hidden'); document.getElementById('createQuizBtn').classList.remove('hidden'); // Clear session data sessionStorage.removeItem('currentQuiz'); sessionStorage.removeItem('currentQuestionIndex'); sessionStorage.removeItem('userAnswers'); sessionStorage.removeItem('score'); } // Global file processing function function processFile() { console.log('🔄 FĂĄjl feldolgozĂĄs indĂ­tĂĄsa...'); // 1. A kivĂĄlasztott fĂĄjl(ok) lekĂ©rĂ©se const fileInput = document.getElementById('fileInput'); let file = null; if (fileInput && fileInput.files && fileInput.files.length > 0) { file = fileInput.files[0]; } else if (lastSelectedFile) { file = lastSelectedFile; } // EllenƑrzĂ©s, hogy van-e fĂĄjl kivĂĄlasztva if (!file) { showNotification('VĂĄlassz ki egy fĂĄjlt a feldolgozĂĄshoz!', 'error'); return; } console.log('📁 KivĂĄlasztott fĂĄjl:', file.name, 'MĂ©ret:', (file.size / 1024 / 1024).toFixed(2), 'MB'); // 2. FĂĄjlfeldolgozĂĄs a fĂĄjltĂ­pus alapjĂĄn const fileExtension = file.name.split('.').pop().toLowerCase(); // FĂĄjl olvasĂł inicializĂĄlĂĄsa const reader = new FileReader(); reader.onload = function(event) { const fileContent = event.target.result; let resultData = null; let extractedText = ''; console.log('📖 FĂĄjl beolvasva, feldolgozĂĄs tĂ­pus szerint...'); switch (fileExtension) { case 'docx': console.log('📄 DOCX fĂĄjl feldolgozĂĄsa Mammoth.js-szel...'); // EllenƑrizzĂŒk, hogy a Mammoth könyvtĂĄr elĂ©rhetƑ-e if (typeof mammoth === 'undefined') { showNotification('❌ Mammoth könyvtĂĄr nem elĂ©rhetƑ! EllenƑrizd az internet kapcsolatot.', 'error'); return; } // DOCX fĂĄjl feldolgozĂĄsa a Mammoth.js-szel (ArrayBuffer kell neki) mammoth.extractRawText({arrayBuffer: fileContent}) .then(function(result){ // A kinyert szöveges tartalom extractedText = result.value; console.log("✅ DOCX tartalom kiolvasva. Szöveg hossza:", extractedText.length); console.log("📝 ElƑnĂ©zet:", extractedText.substring(0, 200) + '...'); if (result.messages && result.messages.length > 0) { console.log("⚠ Mammoth ĂŒzenetek:", result.messages); } // Szöveg beillesztĂ©se a kvĂ­z kĂ©szĂ­tƑ mezƑbe fillTextImportField(extractedText); showNotification(`✅ Word fĂĄjl sikeresen feldolgozva! ${extractedText.length} karakter kinyerve.`, 'success'); }) .catch(function(error) { console.error("❌ DOCX feldolgozĂĄsi hiba:", error); showNotification('Hiba a Word fĂĄjl feldolgozĂĄsakor: ' + error.message, 'error'); }); break; case 'xlsx': case 'xls': console.log('📊 Excel fĂĄjl feldolgozĂĄsa XLSX.js-szel...'); // EllenƑrizzĂŒk, hogy az XLSX könyvtĂĄr elĂ©rhetƑ-e if (typeof XLSX === 'undefined') { showNotification('❌ XLSX könyvtĂĄr nem elĂ©rhetƑ! EllenƑrizd az internet kapcsolatot.', 'error'); return; } try { // XLSX fĂĄjl feldolgozĂĄsa az XLSX.js-szel (ArrayBuffer kell neki) const workbook = XLSX.read(fileContent, { type: 'array' }); console.log('📋 Munkalapok:', workbook.SheetNames); // Az elsƑ munkalap adatait JSON formĂĄban kiolvassa const firstSheetName = workbook.SheetNames[0]; const worksheet = workbook.Sheets[firstSheetName]; // Sorok tömbjekĂ©nt olvassuk ki (header: 1 = elsƑ sor is adat) const jsonData = XLSX.utils.sheet_to_json(worksheet, {header: 1}); console.log("✅ Excel tartalom kiolvasva. Sorok szĂĄma:", jsonData.length); console.log("📊 ElsƑ nĂ©hĂĄny sor:", jsonData.slice(0, 3)); // Excel adatok szöveggĂ© konvertĂĄlĂĄsa (tab-bal elvĂĄlasztva) extractedText = jsonData .filter(row => row && row.some(cell => cell && cell.toString().trim())) // Üres sorok kiszƱrĂ©se .map(row => row.map(cell => cell || '').join('\t')) // Tab-bal elvĂĄlasztĂĄs .join('\n'); console.log("📝 KonvertĂĄlt szöveg hossza:", extractedText.length); // Szöveg beillesztĂ©se a kvĂ­z kĂ©szĂ­tƑ mezƑbe fillTextImportField(extractedText); showNotification(`✅ Excel fĂĄjl sikeresen feldolgozva! ${jsonData.length} sor feldolgozva.`, 'success'); } catch (error) { console.error("❌ Excel feldolgozĂĄsi hiba:", error); showNotification('Hiba az Excel fĂĄjl feldolgozĂĄsakor: ' + error.message, 'error'); } break; case 'txt': console.log('📝 Szöveges fĂĄjl feldolgozĂĄsa...'); // TXT fĂĄjl feldolgozĂĄsa (szövegkĂ©nt olvassa ki) extractedText = fileContent; console.log("✅ Szöveges tartalom kiolvasva. Karakterek szĂĄma:", extractedText.length); console.log("📝 ElƑnĂ©zet:", extractedText.substring(0, 200) + '...'); // Szöveg beillesztĂ©se a kvĂ­z kĂ©szĂ­tƑ mezƑbe fillTextImportField(extractedText); showNotification(`✅ Szöveges fĂĄjl sikeresen feldolgozva! ${extractedText.length} karakter kinyerve.`, 'success'); break; default: console.error('❌ Nem tĂĄmogatott fĂĄjltĂ­pus:', fileExtension); showNotification(`❌ Nem tĂĄmogatott fĂĄjltĂ­pus: .${fileExtension}. Csak .docx, .xlsx Ă©s .txt fĂĄjlok tĂĄmogatottak.`, 'error'); } }; reader.onerror = function(error) { console.error('❌ FĂĄjl olvasĂĄsi hiba:', error); showNotification('Hiba törtĂ©nt a fĂĄjl olvasĂĄsakor!', 'error'); }; // 3. A FileReader indĂ­tĂĄsa (eldönti, hogy ArrayBuffer vagy Text kell) showNotification('📖 FĂĄjl beolvasĂĄsa...', 'info'); if (fileExtension === 'docx' || fileExtension === 'xlsx' || fileExtension === 'xls') { // BinĂĄris fĂĄjlokhoz (Word, Excel) ArrayBuffer-kĂ©nt kell kiolvasni console.log('🔄 ArrayBuffer mĂłdban olvasom a fĂĄjlt...'); reader.readAsArrayBuffer(file); } else { // Szöveges fĂĄjlokhoz Text-kĂ©nt console.log('🔄 Szöveg mĂłdban olvasom a fĂĄjlt...'); reader.readAsText(file, 'UTF-8'); } } // SegĂ©dfĂŒggvĂ©ny a szöveg beillesztĂ©sĂ©hez function fillTextImportField(text) { const textImportField = document.getElementById('importText'); if (textImportField) { textImportField.value = text; console.log('📝 Szöveg beillesztve a kvĂ­z kĂ©szĂ­tƑ mezƑbe'); // Scroll to the text field to show the user textImportField.scrollIntoView({ behavior: 'smooth', block: 'center' }); // Brief highlight effect textImportField.style.borderColor = 'var(--success)'; setTimeout(() => { textImportField.style.borderColor = 'var(--border-color)'; }, 2000); showNotification('📝 Szöveg beillesztve! Most vĂĄlaszd ki a kvĂ­z tĂ­pusĂĄt Ă©s hozd lĂ©tre.', 'info'); } else { console.warn('⚠ Szöveg import mezƑ nem talĂĄlhatĂł!'); } } // Settings functions function saveQuizSettings() { const settings = { questionOrder: document.getElementById('questionOrder').value, allowSkip: document.getElementById('allowSkip').value === 'true', questionTimeLimit: parseInt(document.getElementById('questionTimeLimit').value) || 0, totalTimeLimit: parseInt(document.getElementById('totalTimeLimit').value) || 0, randomQuestionCount: parseInt(document.getElementById('randomQuestionCount').value) || 0, notifications: document.getElementById('notifications').checked, soundEffects: document.getElementById('soundEffects').checked }; localStorage.setItem('quizSettings', JSON.stringify(settings)); // Setup push notifications if enabled if (settings.notifications) { setupPushNotifications(); } else { disablePushNotifications(); } showNotification('BeĂĄllĂ­tĂĄsok mentve!', 'success'); } // Push Notification Functions async function setupPushNotifications() { if (!('Notification' in window)) { showNotification('Ez a böngĂ©szƑ nem tĂĄmogatja az Ă©rtesĂ­tĂ©seket', 'warning'); return; } if (Notification.permission === 'granted') { scheduleDailyReminder(); } else if (Notification.permission !== 'denied') { const permission = await Notification.requestPermission(); if (permission === 'granted') { scheduleDailyReminder(); showNotification('ÉrtesĂ­tĂ©sek engedĂ©lyezve! Napi emlĂ©keztetƑket fogsz kapni.', 'success'); } else { showNotification('ÉrtesĂ­tĂ©sek letiltva', 'info'); } } } function scheduleDailyReminder() { // Clear existing reminders const existingReminder = localStorage.getItem('dailyReminderTimeout'); if (existingReminder) { clearTimeout(parseInt(existingReminder)); } // Calculate time until next 9 AM const now = new Date(); const tomorrow9AM = new Date(); tomorrow9AM.setDate(now.getDate() + 1); tomorrow9AM.setHours(9, 0, 0, 0); const timeUntilReminder = tomorrow9AM.getTime() - now.getTime(); // Schedule the reminder const timeoutId = setTimeout(() => { sendDailyReminder(); // Schedule next day's reminder scheduleDailyReminder(); }, timeUntilReminder); localStorage.setItem('dailyReminderTimeout', timeoutId.toString()); } function sendDailyReminder() { if (Notification.permission === 'granted') { const messages = [ '📚 Ideje gyakorolni! VĂĄlassz egy kvĂ­zt Ă©s fejleszd tudĂĄsodat!', '🎯 Napi gyakorlĂĄs ideje! Melyik tĂ©mĂĄt szeretnĂ©d ma ĂĄtismĂ©telni?', '⭐ Egy kis tanulĂĄs minden nap csodĂĄkat tesz! KezdjĂŒnk?', '🧠 Agyad kĂ©szen ĂĄll az Ășj kihĂ­vĂĄsokra! IndĂ­ts egy kvĂ­zt!', '📖 A tudĂĄs hatalom! Gyakorolj ma is egy kicsit!' ]; const randomMessage = messages[Math.floor(Math.random() * messages.length)]; const notification = new Notification('VIZSGApp - Napi emlĂ©keztetƑ', { body: randomMessage, icon: 'data:image/svg+xml,📚', badge: 'data:image/svg+xml,📚', tag: 'daily-reminder', requireInteraction: false, silent: false }); notification.onclick = function() { window.focus(); notification.close(); }; // Auto close after 10 seconds setTimeout(() => notification.close(), 10000); } } function disablePushNotifications() { const existingReminder = localStorage.getItem('dailyReminderTimeout'); if (existingReminder) { clearTimeout(parseInt(existingReminder)); localStorage.removeItem('dailyReminderTimeout'); } } // Achievement notifications function sendAchievementNotification(title, message) { if (Notification.permission === 'granted') { const notification = new Notification(title, { body: message, icon: 'data:image/svg+xml,🏆', tag: 'achievement', requireInteraction: true }); notification.onclick = function() { window.focus(); notification.close(); }; } } function loadQuizSettings() { const settings = JSON.parse(localStorage.getItem('quizSettings') || '{}'); if (document.getElementById('questionOrder')) { document.getElementById('questionOrder').value = settings.questionOrder || 'original'; document.getElementById('allowSkip').value = settings.allowSkip ? 'true' : 'false'; document.getElementById('questionTimeLimit').value = settings.questionTimeLimit || ''; document.getElementById('totalTimeLimit').value = settings.totalTimeLimit || ''; document.getElementById('randomQuestionCount').value = settings.randomQuestionCount || ''; document.getElementById('notifications').checked = settings.notifications || false; document.getElementById('soundEffects').checked = settings.soundEffects || false; } // Setup notifications if enabled if (settings.notifications) { setupPushNotifications(); } } function checkAchievements(percentage, correct, total) { const achievements = JSON.parse(localStorage.getItem('achievements') || '[]'); const newAchievements = []; // Perfect score achievement if (percentage === 100 && !achievements.includes('perfect_score')) { achievements.push('perfect_score'); newAchievements.push({ title: '🏆 TökĂ©letes!', message: 'ElĂ©rtĂ©l 100%-ot egy kvĂ­zben!' }); } // High score achievement if (percentage >= 90 && !achievements.includes('high_score')) { achievements.push('high_score'); newAchievements.push({ title: '⭐ KivĂĄlĂł!', message: 'ElĂ©rtĂ©l 90% feletti eredmĂ©nyt!' }); } // First quiz achievement if (!achievements.includes('first_quiz')) { achievements.push('first_quiz'); newAchievements.push({ title: '🎯 ElsƑ kvĂ­z!', message: 'GratulĂĄlok az elsƑ befejezett kvĂ­zedhez!' }); } // Long quiz achievement if (total >= 20 && !achievements.includes('long_quiz')) { achievements.push('long_quiz'); newAchievements.push({ title: '📚 KitartĂł!', message: 'Befejezett egy 20+ kĂ©rdĂ©ses kvĂ­zt!' }); } // Save achievements localStorage.setItem('achievements', JSON.stringify(achievements)); // Show new achievements newAchievements.forEach(achievement => { setTimeout(() => { sendAchievementNotification(achievement.title, achievement.message); showNotification(achievement.title + ' ' + achievement.message, 'success'); }, 1000); }); } function saveQuizResult(quiz, correct, total, percentage) { const results = JSON.parse(localStorage.getItem('quizResults') || '[]'); const result = { quizId: quiz.id, quizTitle: quiz.title, quizType: quiz.type, correct: correct, total: total, percentage: percentage, date: new Date().toISOString(), timeSpent: window.totalTimeRemaining ? (JSON.parse(localStorage.getItem('quizSettings') || '{}').totalTimeLimit * 60 - window.totalTimeRemaining) : 0 }; results.push(result); // Keep only last 100 results if (results.length > 100) { results.splice(0, results.length - 100); } localStorage.setItem('quizResults', JSON.stringify(results)); } function exportData() { const data = { quizzes: JSON.parse(localStorage.getItem('localQuizzes') || '[]'), settings: JSON.parse(localStorage.getItem('quizSettings') || '{}'), theme: localStorage.getItem('theme') || 'light' }; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `vizsga-app-backup-${new Date().toISOString().split('T')[0]}.json`; a.click(); URL.revokeObjectURL(url); showNotification('Adatok exportĂĄlva!', 'success'); } function importData() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.onchange = (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { try { const data = JSON.parse(e.target.result); if (data.quizzes) { localStorage.setItem('localQuizzes', JSON.stringify(data.quizzes)); } if (data.settings) { localStorage.setItem('quizSettings', JSON.stringify(data.settings)); } if (data.theme) { localStorage.setItem('theme', data.theme); currentTheme = data.theme; document.documentElement.setAttribute('data-theme', data.theme); updateThemeToggle(); } loadData(); loadQuizSettings(); showNotification('Adatok importĂĄlva!', 'success'); } catch (error) { showNotification('HibĂĄs fĂĄjl formĂĄtum!', 'error'); } }; reader.readAsText(file); }; input.click(); } function clearLocalData() { if (confirm('Biztosan törölni szeretnĂ©d az összes helyi adatot? Ez nem visszavonhatĂł!')) { localStorage.removeItem('localQuizzes'); localStorage.removeItem('quizSettings'); quizzes = []; updateQuizzesList(); updateStats(); showNotification('Helyi adatok törölve!', 'success'); } } // Check for authentication state changes if (supabase) { supabase.auth.onAuthStateChange((event, session) => { if (event === 'SIGNED_IN') { currentUser = session.user; isLoggedIn = true; updateHeaderActions(); updateProfileSettings(); loadUserQuizzes(); loadUserMarketplaceQuizzes(); } else if (event === 'SIGNED_OUT') { currentUser = null; isLoggedIn = false; updateHeaderActions(); updateProfileSettings(); quizzes = []; marketplaceQuizzes = []; updateQuizzesList(); updateMarketplaceQuizzesList(); updateStats(); } }); } function updateProfileSettings() { const loggedInSettings = document.getElementById('loggedInSettings'); const loggedOutSettings = document.getElementById('loggedOutSettings'); const userEmail = document.getElementById('userEmail'); if (isLoggedIn && currentUser) { loggedInSettings.classList.remove('hidden'); loggedOutSettings.classList.add('hidden'); if (userEmail) userEmail.value = currentUser.email; } else { loggedInSettings.classList.add('hidden'); loggedOutSettings.classList.remove('hidden'); } } // --- Marketplace filters --- function getMarketplaceFilterValues(){ const q = (document.getElementById('searchMarketplace')?.value || '').toLowerCase().trim(); const cat = (document.getElementById('filterCategory')?.value || '').toLowerCase().trim(); const aud = (document.getElementById('filterAudience')?.value || '').toLowerCase().trim(); return {q, cat, aud}; } function filteredItems(items){ const {q, cat, aud} = getMarketplaceFilterValues(); return items.filter(it => { const title = (it.title || it.quiz_data?.title || '').toLowerCase(); const desc = (it.description || '').toLowerCase(); const tags = (it.tags || []).join(' ').toLowerCase(); const itemCat = (it.category || '').toLowerCase(); const itemAud = (it.target_audience || '').toLowerCase(); const matchesQ = !q || title.includes(q) || desc.includes(q) || tags.includes(q); const matchesCat = !cat || itemCat === cat; const matchesAud = !aud || itemAud === aud; return matchesQ && matchesCat && matchesAud; }); } async function loadMarketplaceItems(){ const container = document.getElementById('marketplaceItems'); if (!supabase) { container.innerHTML = '
⚙

Supabase beĂĄllĂ­tĂĄs szĂŒksĂ©ges a piactĂ©r hasznĂĄlatĂĄhoz

'; return; } try{ const { data, error } = await supabase .from('marketplace_quizzes') .select('*') .order('created_at', { ascending: false }); if (error) throw error; window.__marketItems = data || []; populateCategoryFilter(window.__marketItems); renderMarketplaceItems(); bindMarketplaceFilterEvents(); }catch(err){ console.error('Error loading marketplace items:', err); container.innerHTML = '
❌

Hiba történt a piactér betöltésekor

'; } } function populateCategoryFilter(items){ const select = document.getElementById('filterCategory'); if (!select) return; const cats = Array.from(new Set(items.map(i => (i.category||'').trim()).filter(Boolean))).sort((a,b)=>a.localeCompare(b,'hu')); select.innerHTML = '' + cats.map(c=>``).join(''); // also fill upload category list const up = document.getElementById('marketplaceCategory'); if (up) up.innerHTML = '' + cats.map(c=>``).join(''); } function bindMarketplaceFilterEvents(){ const ids = ['searchMarketplace','filterCategory','filterAudience']; ids.forEach(id=>{ const el = document.getElementById(id); if (el && !el.__bound){ el.addEventListener('input', renderMarketplaceItems); el.addEventListener('change', renderMarketplaceItems); el.__bound = true; } }); } function renderMarketplaceItems(){ const container = document.getElementById('marketplaceItems'); const items = filteredItems(window.__marketItems || []); if (items.length === 0){ container.innerHTML = '
Nincs talĂĄlat a szƱrƑk alapjĂĄn
'; return; } container.innerHTML = items.map(item => `

${item.title || item.quiz_data?.title || 'Ismeretlen cĂ­m'}

${item.category ? 'Kategória: '+item.category : ''} ${item.target_audience ? ' ‱ Korosztály: '+item.target_audience : ''}
${item.price_type==='paid' ? (item.price||0)+' Ft' : (item.price_type==='password'?'Jelszóval védett':'Ingyenes')}

${item.description||''}

${item.tags && item.tags.length ? `
${item.tags.map(t=>`${t}`).join('')}
`:''}
`).join(''); } // ===== Marketplace acquisition helpers (free / password-protected) ===== async function attemptAcquireMarketplaceQuiz(mpId) { // Load marketplace item let { data: mpRows, error: mErr } = await supabase.from('marketplace_quizzes').select('*').eq('id', mpId).limit(1); if (mErr) throw mErr; if (!mpRows || mpRows.length === 0) throw new Error('A tétel nem talålható.'); const mp = mpRows[0]; // Handle password if needed if (mp.price_type === 'password') { const entered = prompt('Ez a kvíz jelszóval védett. Add meg a jelszót:'); if (!entered) { showNotification('MƱvelet megszakítva.', 'info'); return; } if (entered.trim() !== (mp.password || '')) { showNotification('Hibås jelszó!', 'error'); return; } } // Fetch original quiz data let { data: quizRows, error: qErr } = await supabase.from('quizzes').select('*').eq('id', mp.quiz_id).limit(1); if (qErr) throw qErr; if (!quizRows || quizRows.length === 0) throw new Error('Kapcsolt kvíz nem talålható.'); const quiz = quizRows[0]; // Insert into user_marketplace_quizzes (user's library) const payload = { user_id: currentUser.id, marketplace_quiz_id: mp.id, quiz_data: { id: quiz.id, title: quiz.title, description: quiz.description, type: quiz.type, category: quiz.category, questions: quiz.questions } }; let { data: addRow, error: addErr } = await supabase.from('user_marketplace_quizzes').insert([payload]).select().limit(1); if (addErr) throw addErr; showNotification('A kvíz hozzåadva a piactér kvízeidhez!', 'success'); try { loadMarketplaceData?.(); } catch(e) {} } // --- EXTRA: Populate 'mpExistingQuizSelect' when marketplace upload modal opens --- (function(){ function populateMpExisting(){ try{ const sel = document.getElementById('mpExistingQuizSelect'); if (!sel) return; sel.innerHTML = ''; (Array.isArray(quizzes)?quizzes:[]).forEach(q=>{ if (!q || !q.id || !q.title) return; const opt = document.createElement('option'); opt.value = q.id; opt.textContent = q.title; sel.appendChild(opt); }); }catch(e){ console.warn('mpExistingQuizSelect populate skipped', e); } } const btn = document.getElementById('uploadToMarketplaceBtn'); if (btn) btn.addEventListener('click', ()=> setTimeout(populateMpExisting, 100)); const modal = document.getElementById('marketplaceUploadModal'); if (modal) { const obs = new MutationObserver(()=>{ if (modal.classList.contains('active')) populateMpExisting(); }); obs.observe(modal, {attributes:true, attributeFilter:['class']}); } })();