NexIMPERA
would // otherwise terminate this block and execute for every quiz taker. const QUIZ_DATA = {"quiz":{"id":"1","title":"Financial Literacy Fundamentals","slug":"financial-literacy-fundamentals","description":"Test your understanding of basic financial concepts, investment instruments, and wealth management principles. This quiz covers essential topics every investor should know.","cover_image":null,"category":"Financial Literacy","difficulty":"medium","time_limit":"15","passing_score":"60","max_attempts":"0","is_active":"1","approval_status":"approved","approved_by":null,"approved_at":null,"rejection_note":null,"is_featured":"1","show_answers":"1","randomize_questions":"0","created_by":"1","created_at":"2026-06-07 07:43:31","updated_at":"2026-07-14 12:35:11"},"questions":[{"id":"1","quiz_id":"1","question":"What does \u0022SIP\u0022 stand for in mutual fund investments?","question_type":"single","explanation":"SIP stands for Systematic Investment Plan — a method of investing a fixed amount in mutual funds at regular intervals.","points":"2","order_num":"1","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"1","question_id":"1","option_text":"Simple Investment Plan","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"2","question_id":"1","option_text":"Systematic Investment Plan","is_correct":"1","order_num":"2","is_deleted":"0"},{"id":"3","question_id":"1","option_text":"Secure Income Portfolio","is_correct":"0","order_num":"3","is_deleted":"0"},{"id":"4","question_id":"1","option_text":"Standard Interest Payment","is_correct":"0","order_num":"4","is_deleted":"0"}]},{"id":"2","quiz_id":"1","question":"Which of the following is considered a \u0022safe haven\u0022 asset?","question_type":"single","explanation":"Gold is traditionally considered a safe haven asset as it tends to retain value during economic uncertainty.","points":"2","order_num":"2","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"5","question_id":"2","option_text":"Cryptocurrency","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"6","question_id":"2","option_text":"Gold","is_correct":"1","order_num":"2","is_deleted":"0"},{"id":"7","question_id":"2","option_text":"Real Estate","is_correct":"0","order_num":"3","is_deleted":"0"},{"id":"8","question_id":"2","option_text":"Technology Stocks","is_correct":"0","order_num":"4","is_deleted":"0"}]},{"id":"3","quiz_id":"1","question":"What is the primary purpose of diversification in a portfolio?","question_type":"single","explanation":"Diversification spreads investments across different asset classes to reduce the impact of any single investment performing poorly.","points":"2","order_num":"3","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"9","question_id":"3","option_text":"To maximize returns on a single investment","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"10","question_id":"3","option_text":"To reduce overall portfolio risk","is_correct":"1","order_num":"2","is_deleted":"0"},{"id":"11","question_id":"3","option_text":"To minimize tax liability","is_correct":"0","order_num":"3","is_deleted":"0"},{"id":"12","question_id":"3","option_text":"To track market indices closely","is_correct":"0","order_num":"4","is_deleted":"0"}]},{"id":"4","quiz_id":"1","question":"The term \u0022Bull Market\u0022 refers to:","question_type":"single","explanation":"A Bull Market is characterized by rising prices and investor optimism. The term comes from the way a bull attacks — thrusting upward.","points":"2","order_num":"4","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"13","question_id":"4","option_text":"A market with falling prices and pessimism","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"14","question_id":"4","option_text":"A market with rising prices and optimism","is_correct":"1","order_num":"2","is_deleted":"0"},{"id":"15","question_id":"4","option_text":"A stagnant market with no movement","is_correct":"0","order_num":"3","is_deleted":"0"},{"id":"16","question_id":"4","option_text":"A market controlled by a few large investors","is_correct":"0","order_num":"4","is_deleted":"0"}]},{"id":"5","quiz_id":"1","question":"What is compound interest?","question_type":"single","explanation":"Compound interest is interest calculated on both the initial principal and the accumulated interest from previous periods — often called \u0022interest on interest.\u0022","points":"2","order_num":"5","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"17","question_id":"5","option_text":"Interest only on the original principal","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"18","question_id":"5","option_text":"Interest on principal plus accumulated interest","is_correct":"1","order_num":"2","is_deleted":"0"},{"id":"19","question_id":"5","option_text":"A fixed interest rate guaranteed by government","is_correct":"0","order_num":"3","is_deleted":"0"},{"id":"20","question_id":"5","option_text":"Interest that is tax-free","is_correct":"0","order_num":"4","is_deleted":"0"}]},{"id":"6","quiz_id":"1","question":"SEBI stands for:","question_type":"single","explanation":"SEBI stands for Securities and Exchange Board of India — the regulatory body for securities and commodity markets in India.","points":"2","order_num":"6","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"21","question_id":"6","option_text":"Stock Exchange Board of India","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"22","question_id":"6","option_text":"Securities Exchange Bureau of India","is_correct":"0","order_num":"2","is_deleted":"0"},{"id":"23","question_id":"6","option_text":"Securities and Exchange Board of India","is_correct":"1","order_num":"3","is_deleted":"0"},{"id":"24","question_id":"6","option_text":"Standard Economic Bureau of India","is_correct":"0","order_num":"4","is_deleted":"0"}]},{"id":"7","quiz_id":"1","question":"Which investment type typically offers the highest potential returns over a long period?","question_type":"single","explanation":"Equities (stocks) have historically provided the highest returns over long periods, though they come with higher short-term volatility.","points":"2","order_num":"7","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"25","question_id":"7","option_text":"Fixed Deposits","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"26","question_id":"7","option_text":"Government Bonds","is_correct":"0","order_num":"2","is_deleted":"0"},{"id":"27","question_id":"7","option_text":"Equities (Stocks)","is_correct":"1","order_num":"3","is_deleted":"0"},{"id":"28","question_id":"7","option_text":"Savings Account","is_correct":"0","order_num":"4","is_deleted":"0"}]},{"id":"8","quiz_id":"1","question":"What does NAV represent in mutual funds?","question_type":"single","explanation":"NAV stands for Net Asset Value — the per-unit market value of a mutual fund scheme.","points":"2","order_num":"8","created_at":"2026-06-07 07:43:31","is_deleted":"0","options":[{"id":"29","question_id":"8","option_text":"Net Annual Value","is_correct":"0","order_num":"1","is_deleted":"0"},{"id":"30","question_id":"8","option_text":"National Asset Valuation","is_correct":"0","order_num":"2","is_deleted":"0"},{"id":"31","question_id":"8","option_text":"Net Asset Value","is_correct":"1","order_num":"3","is_deleted":"0"},{"id":"32","question_id":"8","option_text":"Nominal Average Value","is_correct":"0","order_num":"4","is_deleted":"0"}]}]}; const SITE_URL = 'https://neximpera.com'; const USER_ID = null; // Unlimited label generator: A,B...Z,AA,AB...ZZ,AAA... function indexToLabel(i) { const alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; if (i < 26) return alpha[i]; let label = ''; i++; while (i > 0) { i--; label = alpha[i % 26] + label; i = Math.floor(i / 26); } return label; } let currentQ = 0; let answers = {}; // { question_id: { selected: [optId, ...] } } let attemptId = null; let startTime = null; let timerInterval = null; let userInfo = {}; document.getElementById('userInfoForm').addEventListener('submit', async (e) => { e.preventDefault(); const form = e.target; userInfo = { name: form.name.value.trim(), email: form.email.value.trim(), phone: form.phone.value.trim(), city: form.city.value.trim(), occupation: form.occupation.value.trim(), experience: form.experience.value, quiz_id: QUIZ_DATA.quiz.id, user_id: USER_ID }; const btn = document.getElementById('startQuizBtn'); btn.disabled = true; btn.textContent = 'Starting…'; try { const res = await fetch(SITE_URL + '/api/quiz.php?action=start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(userInfo) }); const data = await res.json(); if (data.success) { attemptId = data.attempt_id; startTime = Date.now(); document.getElementById('userInfoModal').classList.remove('active'); document.getElementById('quizInterface').style.display = 'block'; renderQuestion(); if (QUIZ_DATA.quiz.time_limit > 0) startTimer(QUIZ_DATA.quiz.time_limit * 60); } else { showToast(data.error || 'Error starting quiz', 'error'); btn.disabled = false; btn.textContent = ' Start Quiz'; } } catch(err) { showToast('Network error. Please try again.', 'error'); btn.disabled = false; btn.textContent = ' Start Quiz'; } }); function renderQuestion() { const q = QUIZ_DATA.questions[currentQ]; const total = QUIZ_DATA.questions.length; document.getElementById('questionNum').textContent = `Question ${currentQ + 1} of ${total}`; document.getElementById('questionCounter').textContent = `Q${currentQ+1}/${total}`; document.getElementById('questionText').textContent = q.question; document.getElementById('progressFill').style.width = (currentQ / total * 100) + '%'; // Type hint const hint = document.getElementById('questionTypeHint'); if (q.question_type === 'multiple') { hint.textContent = ' Select all correct answers'; hint.style.display = 'block'; } else { hint.style.display = 'none'; } const list = document.getElementById('optionsList'); list.innerHTML = ''; q.options.forEach((opt, i) => { const div = document.createElement('div'); div.className = 'quiz-option'; div.dataset.id = opt.id; const label = indexToLabel(i); // A, B, C ... Z, AA, AB ... div.innerHTML = `
${escapeHtml(label)}
${escapeHtml(opt.option_text)}
`; // Restore prior selection if (answers[q.id] && answers[q.id].selected.includes(opt.id)) { div.classList.add('selected'); } div.addEventListener('click', () => selectOption(div, opt.id, q)); list.appendChild(div); }); const expBox = document.getElementById('explanation'); if (answers[q.id]) { showExplanation(q); markOptions(q); } else { expBox.style.display = 'none'; } // Dot nav const dots = document.getElementById('dotNav'); dots.innerHTML = ''; const maxDots = Math.min(total, 20); for (let i = 0; i < maxDots; i++) { const d = document.createElement('div'); d.style.cssText = `width:8px;height:8px;border-radius:50%;transition:all 0.25s;cursor:pointer;background:${i===currentQ?'var(--gold)':answers[QUIZ_DATA.questions[i].id]?'var(--teal)':'var(--border-subtle)'}`; d.title = `Question ${i+1}`; const idx = i; d.onclick = () => { currentQ = idx; renderQuestion(); }; dots.appendChild(d); } if (total > 20) { const more = document.createElement('span'); more.style.cssText = 'font-size:11px;color:var(--text-muted);padding:0 4px'; more.textContent = `+${total - 20} more`; dots.appendChild(more); } document.getElementById('prevBtn').style.visibility = currentQ > 0 ? 'visible' : 'hidden'; const nextBtn = document.getElementById('nextBtn'); nextBtn.textContent = currentQ === total - 1 ? 'Submit Quiz ✓' : 'Next →'; } function selectOption(div, optId, q) { if (answers[q.id]) return; // already answered if (q.question_type === 'multiple') { // Toggle for multiple choice if (!answers[q.id]) answers[q.id] = { selected: [] }; const idx = answers[q.id].selected.indexOf(optId); if (idx === -1) { answers[q.id].selected.push(optId); div.classList.add('selected'); } else { answers[q.id].selected.splice(idx, 1); div.classList.remove('selected'); } // For multiple: don't lock until Next is clicked return; } // Single / true_false: lock immediately document.querySelectorAll('.quiz-option').forEach(o => o.classList.remove('selected')); div.classList.add('selected'); answers[q.id] = { selected: [optId] }; showExplanation(q); markOptions(q); } function markOptions(q) { const ans = answers[q.id]; if (!ans) return; const correctIds = q.options.filter(o => parseInt(o.is_correct)).map(o => o.id); document.querySelectorAll('.quiz-option').forEach(opt => { const id = parseInt(opt.dataset.id); const isSelected = ans.selected.includes(id); const isCorrect = correctIds.includes(id); opt.classList.remove('selected'); if (isSelected && isCorrect) opt.classList.add('correct'); else if (isSelected) opt.classList.add('wrong'); else if (isCorrect) opt.classList.add('correct'); }); } function showExplanation(q) { if (q.explanation && QUIZ_DATA.quiz.show_answers === '1') { document.getElementById('explanationText').textContent = q.explanation; document.getElementById('explanation').style.display = 'block'; } } function prevQuestion() { if (currentQ > 0) { currentQ--; renderQuestion(); } } async function nextQuestion() { const q = QUIZ_DATA.questions[currentQ]; const isMultiple = q.question_type === 'multiple'; // For multiple-choice, lock & mark on Next if (isMultiple && !answers[q.id]) { const selected = [...document.querySelectorAll('.quiz-option.selected')].map(d => parseInt(d.dataset.id)); if (!selected.length) { showToast('Select at least one answer', 'info'); return; } answers[q.id] = { selected }; markOptions(q); showExplanation(q); return; // let them see feedback before moving } if (!answers[q.id] && !isMultiple) { showToast('Please select an answer', 'info'); return; } if (currentQ < QUIZ_DATA.questions.length - 1) { currentQ++; renderQuestion(); } else { await submitQuiz(); } } async function submitQuiz() { if (timerInterval) clearInterval(timerInterval); const timeTaken = Math.round((Date.now() - startTime) / 1000); try { const res = await fetch(SITE_URL + '/api/quiz.php?action=submit', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ attempt_id: attemptId, answers, time_taken: timeTaken }) }); const data = await res.json(); if (data.success) showResults(data, timeTaken); else showToast(data.error || 'Submit failed', 'error'); } catch(e) { showToast('Error submitting. Try again.', 'error'); } } function showResults(data, timeTaken) { document.getElementById('quizInterface').style.display = 'none'; document.getElementById('resultsPanel').style.display = 'block'; const score = Math.round(data.score); const passed = score >= parseInt(QUIZ_DATA.quiz.passing_score); // innerHTML, not textContent - these are SVG fragments, and textContent // would render the markup as visible source. document.getElementById('resultEmoji').innerHTML = score >= 80 ? "<\/svg>" : score >= 60 ? "<\/svg>" : "<\/svg>"; document.getElementById('scoreDisplay').textContent = score + '%'; document.getElementById('scoreCircle').style.setProperty('--score-pct', score + '%'); document.getElementById('resultTitle').textContent = passed ? 'Congratulations! You Passed!' : 'Keep Practicing!'; document.getElementById('resultDesc').textContent = passed ? `You scored ${score}% — excellent financial knowledge!` : `You scored ${score}%. Passing score is ${QUIZ_DATA.quiz.passing_score}%. Review and try again!`; document.getElementById('correctCount').textContent = data.correct; document.getElementById('wrongCount').textContent = data.wrong; const m = Math.floor(timeTaken/60), s = timeTaken%60; document.getElementById('timeTaken').textContent = m > 0 ? `${m}m ${s}s` : `${s}s`; document.getElementById('progressFill').style.width = '100%'; if (QUIZ_DATA.quiz.show_answers === '1') { const review = document.getElementById('answerReview'); review.innerHTML = '

Answer Review

'; QUIZ_DATA.questions.forEach((q, i) => { const ans = answers[q.id]; const selectedIds = ans?.selected || []; const correctOpts = q.options.filter(o => parseInt(o.is_correct)); const isCorrect = correctOpts.length && correctOpts.every(co => selectedIds.includes(co.id)) && selectedIds.every(sid => correctOpts.some(co => co.id === sid)); review.innerHTML += `
${isCorrect?'':''}
Q${i+1}: ${escapeHtml(q.question)}
${q.options.map((opt, oi) => { const isSel = selectedIds.includes(opt.id); const isC = parseInt(opt.is_correct); let s = `background:${isSel&&isC?'rgba(45,212,191,0.08)':isSel?'rgba(251,113,133,0.08)':isC?'rgba(45,212,191,0.04)':'transparent'};border:1px solid ${isSel&&isC?'rgba(45,212,191,0.3)':isSel?'rgba(251,113,133,0.3)':isC?'rgba(45,212,191,0.2)':'var(--border-subtle)'};`; return `
${indexToLabel(oi)} ${escapeHtml(opt.option_text)} ${isSel ? `${isC?'✓ Correct':'✗ Wrong'}` : ''} ${!isSel && isC ? `Correct Answer` : ''}
`; }).join('')} ${q.explanation ? `
${escapeHtml(q.explanation)}
` : ''}
`; }); } } function startTimer(seconds) { let rem = seconds; const el = document.getElementById('quizTimer'); timerInterval = setInterval(() => { rem--; const m = Math.floor(rem/60).toString().padStart(2,'0'); const s = (rem%60).toString().padStart(2,'0'); el.textContent = `${m}:${s}`; if (rem <= 60) el.style.color = 'var(--rose)'; if (rem <= 0) { clearInterval(timerInterval); submitQuiz(); } }, 1000); } function escapeHtml(s) { return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); }