// API Bridge — fetches topics and MCQs from the database API // Supplements existing hardcoded CSE_QUESTIONS and NOTES_DATA const API_BASE = '/api/v1/upsc'; // Category mapping: API category -> tab key const CATEGORY_MAP = { 'Ancient India': 'ancient', 'Medieval India': 'medieval', 'Modern India': 'modern', 'Indian Polity': 'polity', 'Geography': 'indgeo' }; let apiTopics = []; let apiLoaded = false; async function loadAPITopics() { try { const res = await fetch(`${API_BASE}/topics`); if (!res.ok) return; apiTopics = await res.json(); apiLoaded = true; // Update topic count badge const countEl = document.getElementById('api-topic-count'); if (countEl) countEl.textContent = apiTopics.length; const mcqCountEl = document.getElementById('api-mcq-count'); if (mcqCountEl) mcqCountEl.textContent = apiTopics.length * 20; } catch(e) { console.warn('API topics unavailable:', e); } } async function loadAPIMCQs(topicId) { try { const res = await fetch(`${API_BASE}/mcqs/${topicId}`); if (!res.ok) return null; return await res.json(); } catch(e) { return null; } } async function loadAPITopicNotes(topicId) { try { const res = await fetch(`${API_BASE}/topics/${topicId}`); if (!res.ok) return null; return await res.json(); } catch(e) { return null; } } // --- Enhanced MCQ rendering with API data --- const apiRenderedMCQ = {}; const apiMCQScores = {}; function renderAPIMCQSection(tabKey) { const topics = apiTopics.filter(t => CATEGORY_MAP[t.category] === tabKey); if (!topics.length) return; const area = document.getElementById('mcq-render-area'); let existing = document.getElementById('mcq-api-' + tabKey); if (existing) { existing.classList.add('active'); return; } const div = document.createElement('div'); div.id = 'mcq-api-' + tabKey; div.className = 'mcq-container active'; let html = `
`; topics.forEach((t, i) => { const shortTitle = t.title.length > 30 ? t.title.substring(0, 28) + '...' : t.title; html += ``; }); html += `

Loading questions...

`; div.innerHTML = html; area.appendChild(div); // Load first topic's MCQs if (topics.length > 0) loadSubtopicMCQs(topics[0].id, tabKey, null); } async function loadSubtopicMCQs(topicId, tabKey, btn) { // Update button styles if (btn) { const parent = btn.parentElement; parent.querySelectorAll('.mcq-subtopic-btn').forEach(b => { b.style.background = 'none'; b.style.color = 'var(--dim)'; }); btn.style.background = 'var(--accent)'; btn.style.color = '#fff'; } const container = document.getElementById('mcq-api-questions-' + tabKey); if (!container) return; // Check cache if (apiRenderedMCQ[topicId]) { container.innerHTML = apiRenderedMCQ[topicId]; return; } container.innerHTML = '

Loading questions...

'; const data = await loadAPIMCQs(topicId); if (!data || !data.questions) { container.innerHTML = '

Failed to load questions.

'; return; } apiMCQScores[topicId] = { s: 0, t: 0 }; const LETTERS = ['A','B','C','D']; let html = `
Score: 0 / 0  (${data.count} questions)
`; data.questions.forEach((q, i) => { const qId = `api_${topicId}_${i}`; const diffStars = '★'.repeat(q.difficulty) + '☆'.repeat(5 - q.difficulty); const opts = q.options.map((o, j) => `
${LETTERS[j]}) ${o}
`).join(''); html += `
Q${i+1} ${diffStars}
${q.question}
${opts}
${q.explanation}
`; }); container.innerHTML = html; apiRenderedMCQ[topicId] = html; } function answerAPI(opt, qId, choiceIdx, correctIdx, topicId) { if (opt.classList.contains('disabled')) return; const card = opt.closest('.q-card'); const opts = card.querySelectorAll('.opt'); opts.forEach(o => o.classList.add('disabled')); opt.classList.add('selected'); const exp = document.getElementById('exp-' + qId); if (exp) exp.classList.add('show'); if (choiceIdx === correctIdx) { opt.classList.add('correct-ans'); card.classList.add('correct'); } else { opt.classList.add('wrong-ans'); card.classList.add('wrong'); opts[correctIdx].classList.add('correct-ans'); } if (!apiMCQScores[topicId]) apiMCQScores[topicId] = {s:0, t:0}; apiMCQScores[topicId].t++; if (choiceIdx === correctIdx) apiMCQScores[topicId].s++; const scoreEl = document.getElementById('api-score-' + topicId); const totalEl = document.getElementById('api-total-' + topicId); if (scoreEl) scoreEl.textContent = apiMCQScores[topicId].s; if (totalEl) totalEl.textContent = apiMCQScores[topicId].t; } function resetAPIMCQ(topicId, tabKey) { delete apiRenderedMCQ[topicId]; apiMCQScores[topicId] = {s:0, t:0}; loadSubtopicMCQs(topicId, tabKey, null); } // --- Enhanced Notes rendering with API data --- const apiRenderedNotes = {}; function renderAPINotesSection(tabKey) { const topics = apiTopics.filter(t => CATEGORY_MAP[t.category] === tabKey); if (!topics.length) return; const area = document.getElementById('notes-render-area'); let existing = document.getElementById('notes-api-' + tabKey); if (existing) { existing.classList.add('active'); return; } const div = document.createElement('div'); div.id = 'notes-api-' + tabKey; div.className = 'notes-container active'; let html = `
`; topics.forEach((t, i) => { const shortTitle = t.title.length > 35 ? t.title.substring(0, 33) + '...' : t.title; html += ``; }); html += `

Loading notes...

`; div.innerHTML = html; area.appendChild(div); if (topics.length > 0) loadSubtopicNotes(topics[0].id, tabKey, null); } async function loadSubtopicNotes(topicId, tabKey, btn) { if (btn) { const parent = btn.parentElement; parent.querySelectorAll('.notes-subtopic-btn').forEach(b => { b.style.background = 'none'; b.style.color = 'var(--dim)'; }); btn.style.background = 'rgba(15,118,110,0.8)'; btn.style.color = '#fff'; } const container = document.getElementById('notes-api-content-' + tabKey); if (!container) return; if (apiRenderedNotes[topicId]) { container.innerHTML = apiRenderedNotes[topicId]; return; } container.innerHTML = '

Loading notes...

'; const data = await loadAPITopicNotes(topicId); if (!data) { container.innerHTML = '

Failed to load notes.

'; return; } const factsHtml = (data.key_facts || []).map(f => `
  • ${f}
  • `).join(''); const pyqYears = (data.pyq_years || []).join(', '); const crossLinks = (data.cross_links || []).map(l => `${l}`).join(' '); const diffStars = '★'.repeat(data.difficulty || 3) + '☆'.repeat(5 - (data.difficulty || 3)); const weightColor = data.weight === 'high' ? 'var(--green)' : data.weight === 'medium' ? 'var(--yellow)' : 'var(--dim)'; // Convert markdown-ish notes to HTML let notesHtml = (data.notes || '').replace(/## (.*)/g, '

    $1

    ') .replace(/### (.*)/g, '

    $1

    ') .replace(/\*\*(.*?)\*\*/g, '$1') .replace(/\n- /g, '\n• ') .replace(/\n/g, '
    '); let html = `

    ${data.title}

    ${diffStars} ${data.weight || 'medium'} weight
    ${notesHtml}

    Key Facts for Quick Revision

    ${pyqYears ? `
    PYQ Years: ${pyqYears}
    ` : ''} ${crossLinks ? `
    Related Topics: ${crossLinks}
    ` : ''}
    `; container.innerHTML = html; apiRenderedNotes[topicId] = html; } // --- Override switch functions to use API when available --- const origSwitchMCQ = window.switchMCQ; window.switchMCQ = function(topic, btn) { // Hide all containers document.querySelectorAll('.mcq-container').forEach(c => c.classList.remove('active')); document.querySelectorAll('.mcq-topic-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); // Check if API has data for this topic const hasAPI = apiLoaded && apiTopics.some(t => CATEGORY_MAP[t.category] === topic); if (hasAPI) { // Hide old hardcoded version if visible const oldDiv = document.getElementById('mcq-' + topic); if (oldDiv) oldDiv.classList.remove('active'); renderAPIMCQSection(topic); } else { // Fall back to hardcoded const apiDiv = document.getElementById('mcq-api-' + topic); if (apiDiv) apiDiv.classList.remove('active'); renderMCQ(topic); const el = document.getElementById('mcq-' + topic); if (el) el.classList.add('active'); } }; const origSwitchNotes = window.switchNotes; window.switchNotes = function(topic, btn) { document.querySelectorAll('.notes-container').forEach(c => c.classList.remove('active')); document.querySelectorAll('.notes-topic-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); const hasAPI = apiLoaded && apiTopics.some(t => CATEGORY_MAP[t.category] === topic); if (hasAPI) { const oldDiv = document.getElementById('notes-' + topic); if (oldDiv) oldDiv.classList.remove('active'); renderAPINotesSection(topic); } else { const apiDiv = document.getElementById('notes-api-' + topic); if (apiDiv) apiDiv.classList.remove('active'); renderNotes(topic); const el = document.getElementById('notes-' + topic); if (el) el.classList.add('active'); } }; // Load API data on page load and refresh the active tabs loadAPITopics().then(() => { // Re-render ancient history (default tab) with API data if (apiLoaded) { // Remove old hardcoded ancient MCQ const oldMCQ = document.getElementById('mcq-ancient'); if (oldMCQ) oldMCQ.classList.remove('active'); renderAPIMCQSection('ancient'); // Remove old hardcoded ancient notes const oldNotes = document.getElementById('notes-ancient'); if (oldNotes) oldNotes.classList.remove('active'); renderAPINotesSection('ancient'); } });