- Introduced common.js for shared functions including API calls, error reporting, and UI helpers. - Implemented feedback.js for the feedback reporting page, including form handling and displaying feedback status. - Added layout.js for managing galaxy and section layouts in the visualization. - Created login.js for user authentication with session management. - Developed search.js for term searching based on user input and synonyms. - Implemented signup.js for user registration with validation and immediate login.
60 lines
3.4 KiB
JavaScript
60 lines
3.4 KiB
JavaScript
// 내 정보: 로그인한 학생의 반·학습 기록 (로그인 안 했으면 /login 으로)
|
|
import { api, esc, toast } from "./common.js";
|
|
|
|
const main = document.getElementById("main");
|
|
const next = new URLSearchParams(location.search).get("next") || "/";
|
|
|
|
async function load() {
|
|
let me;
|
|
try { me = await api("/api/members/me"); } catch (e) { main.innerHTML = `<p class="muted">불러오지 못했습니다: ${esc(e.message)}</p>`; return; }
|
|
if (!me.logged_in) return renderGuest(me);
|
|
if (me.status === "approved") return renderMember(me);
|
|
main.innerHTML = `<h1>${esc(me.name)} 님</h1>
|
|
<div class="card" style="margin-top:16px">
|
|
<div class="acc-status"><span class="badge new">사용할 수 없는 계정</span>
|
|
<span class="acc-note">담당 교수자에게 문의해 주세요.</span></div>
|
|
<p style="margin-top:14px"><button class="btn" id="logout">로그아웃</button> <a class="btn ghost" href="/">개념 우주로</a></p>
|
|
</div>`;
|
|
document.getElementById("logout").onclick = logout;
|
|
}
|
|
|
|
function renderGuest(me) {
|
|
if (me.admin) {
|
|
main.innerHTML = `<h1>${esc(me.admin)} 님</h1><p class="acc-note">교수자로 로그인되어 있습니다.</p>
|
|
<p><a class="btn primary" href="/admin">관리 화면</a> <a class="btn" href="/members">회원 관리</a></p>`;
|
|
return;
|
|
}
|
|
location.replace("/login?next=" + encodeURIComponent("/account"));
|
|
}
|
|
|
|
async function renderMember(me) {
|
|
const rate = me.attempts ? Math.round((me.correct / me.attempts) * 100) : 0;
|
|
main.innerHTML = `<h1>${esc(me.name)} 님</h1>
|
|
<div class="acc-status"><span class="badge confirmed">승인됨</span><span class="acc-note">${esc(me.class_name || "")}</span>
|
|
<button class="btn small" id="logout">로그아웃</button></div>
|
|
<div class="acc-stats">
|
|
<div class="acc-stat"><small>푼 문제</small><b>${me.attempts}</b></div>
|
|
<div class="acc-stat"><small>맞힌 문제</small><b>${me.correct}</b></div>
|
|
<div class="acc-stat"><small>정답률</small><b>${rate}%</b></div>
|
|
</div>
|
|
<p style="margin-top:14px"><a class="btn primary" href="/#/quiz">문제 풀러 가기</a> <a class="btn" href="/#/quiz/wrong">틀린 문제 다시 풀기</a></p>
|
|
<div class="acc-grid" id="stats"><p class="muted">기록을 불러오는 중…</p></div>`;
|
|
document.getElementById("logout").onclick = logout;
|
|
try {
|
|
const s = await api("/api/members/my-stats");
|
|
document.getElementById("stats").innerHTML = `
|
|
<div class="card"><h2>단원별 정답률</h2>${s.by_galaxy.length ? s.by_galaxy.map((g) => {
|
|
const p = g.attempts ? Math.round((g.correct / g.attempts) * 100) : 0;
|
|
return `<div style="margin-bottom:10px"><div class="row"><span class="grow">${esc(g.name)}</span><span class="acc-note">${g.correct}/${g.attempts} · ${p}%</span></div><div class="bar"><i style="width:${p}%"></i></div></div>`;
|
|
}).join("") : `<p class="acc-note">아직 푼 문제가 없습니다.</p>`}</div>
|
|
<div class="card"><h2>자주 틀린 용어</h2>${s.wrong_terms.length ? `<div class="chips">${s.wrong_terms.map((t) => `<a href="/#/t/${esc(t.term_id)}">${esc(t.name)} · ${t.wrong}</a>`).join("")}</div>` : `<p class="acc-note">틀린 용어가 없습니다.</p>`}</div>`;
|
|
} catch (e) { document.getElementById("stats").innerHTML = `<p class="muted">${esc(e.message)}</p>`; }
|
|
}
|
|
|
|
async function logout() {
|
|
try { await api("/api/members/logout", { method: "POST" }); } catch { /* 무시 */ }
|
|
load();
|
|
}
|
|
|
|
load();
|