126 lines
4.9 KiB
JavaScript
126 lines
4.9 KiB
JavaScript
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 = `<div class="inline-loading"><span class="spinner small"></span>
|
|
<span>기록을 불러오는 중이에요…</span></div>`;
|
|
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 = `<p>아직 저장된 기록이 없습니다.</p>`;
|
|
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 = `
|
|
<div class="insight">
|
|
<div><strong></strong>본 시험</div>
|
|
<div><strong></strong>푼 문제</div>
|
|
<div><strong></strong>평균 정답률</div>
|
|
<div class="${totals.overconfident ? 'danger' : ''}">
|
|
<strong></strong>확신했지만 틀림
|
|
</div>
|
|
</div>
|
|
`;
|
|
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);
|