// 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.questions[0]?.question || quiz.questions[0]?.statement || 'Kérdés betöltése...'}
`;
}
function createFlashcardInterface(quiz) {
return `
KĂĄrtya
${quiz.questions[0]?.concept || quiz.questions[0]?.nativeWord || 'Betöltés...'}
${quiz.questions[0]?.definition || quiz.questions[0]?.foreignWord || ''}
`;
}
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 = `
${percentage >= 80 ? 'đ' : percentage >= 60 ? 'đ' : 'đ'}
${percentage}%
${correctAnswers} / ${quiz.questions.length} helyes vĂĄlasz
${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 = `
${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']});
}
})();