class HistoryPage extends HTMLElement { async connectedCallback() { this.className = 'screen'; this.replaceChildren(createTopbar([createButton('새 시험 시작', () => showStartScreen())])); const heading = document.createElement('h1'); heading.className = 'page-title'; heading.textContent = '지난 기록'; this.appendChild(heading); const body = document.createElement('div'); body.innerHTML = `
기록을 불러오는 중이에요…
`; this.appendChild(body); let tests; try { ({ tests } = await api.tests()); } catch (err) { body.replaceChildren(); const error = document.createElement('p'); error.className = 'error-box'; error.textContent = err.message; body.appendChild(error); return; } if (!tests.length) { body.replaceChildren(); const empty = document.createElement('div'); empty.className = 'card empty'; empty.innerHTML = `

아직 저장된 기록이 없습니다.

`; empty.appendChild( createButton('첫 시험 시작하기', () => showStartScreen(), 'primary') ); body.appendChild(empty); return; } body.replaceChildren(this.renderStats(tests), this.renderList(tests)); } renderStats(tests) { const totals = tests.reduce( (acc, test) => ({ questions: acc.questions + test.score.total, correct: acc.correct + test.score.correct, overconfident: acc.overconfident + test.score.overconfident, }), { questions: 0, correct: 0, overconfident: 0 } ); const card = document.createElement('div'); card.className = 'card'; card.innerHTML = `
본 시험
푼 문제
평균 정답률
확신했지만 틀림
`; const tiles = card.querySelectorAll('.insight strong'); tiles[0].textContent = tests.length; tiles[1].textContent = totals.questions; tiles[2].textContent = `${Math.round((totals.correct / totals.questions) * 100)}%`; tiles[3].textContent = totals.overconfident; card.querySelector('.insight').classList.toggle('risk', totals.overconfident > 0); return card; } renderList(tests) { const list = document.createElement('div'); list.className = 'result-list'; tests.forEach((test) => { const item = document.createElement('button'); item.type = 'button'; item.className = 'card history-item'; item.onclick = () => showHistoryDetail(test.id); const top = document.createElement('div'); top.className = 'history-top'; const range = document.createElement('span'); range.className = 'history-range'; range.textContent = `${test.school} ${test.subject} · ${test.chapter}`; const percent = document.createElement('span'); percent.className = 'history-score'; percent.textContent = `${test.score.percent}점`; top.append(range, percent); const meta = document.createElement('p'); meta.className = 'muted'; meta.textContent = `${test.student} · ${formatDate(test.createdAt)} · ` + `난이도 ${DIFFICULTY_LABEL[test.difficulty] ?? test.difficulty} · ` + `${test.score.total}문제 중 ${test.score.correct}문제 정답`; const tags = document.createElement('p'); tags.className = 'history-tags'; const badges = []; if (test.score.overconfident) { badges.push(['bad', `확신했지만 틀림 ${test.score.overconfident}`]); } if (test.explainedCount) badges.push(['', `해설 ${test.explainedCount}`]); if (test.twinCount) badges.push(['', `쌍둥이 문제 ${test.twinCount}`]); if (test.askedCount) badges.push(['', `후속 질문 ${test.askedCount}`]); badges.forEach(([tone, label]) => { const badge = document.createElement('span'); badge.className = `badge ${tone}`.trim(); badge.textContent = label; tags.appendChild(badge); }); item.append(top, meta, tags); list.appendChild(item); }); return list; } } customElements.define('history-page', HistoryPage);