Merge pull request 'Reports' (#3) from reports into main
Reviewed-on: nmemmert/Spelling#3
This commit is contained in:
commit
14ae64707e
2 files changed
+87
No files matched your search
@@ -51,6 +51,7 @@
|
|||||||
<button onclick="switchTab('tabWords')">📝 Word Lists</button>
|
<button onclick="switchTab('tabWords')">📝 Word Lists</button>
|
||||||
<button onclick="switchTab('tabAnalytics')">📊 Analytics</button>
|
<button onclick="switchTab('tabAnalytics')">📊 Analytics</button>
|
||||||
<button onclick="switchTab('tabResults')">📊 Results</button>
|
<button onclick="switchTab('tabResults')">📊 Results</button>
|
||||||
|
<button onclick="switchTab('tabReports')">📘 Reports</button>
|
||||||
<button onclick="switchTab('tabBadges')">🎖 Badges</button>
|
<button onclick="switchTab('tabBadges')">🎖 Badges</button>
|
||||||
<button onclick="switchTab('tabTheme')">🎨 Theme</button>
|
<button onclick="switchTab('tabTheme')">🎨 Theme</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,6 +142,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 🧾 Student Report Viewer -->
|
||||||
|
<div id="tabReports" class="adminTab hidden">
|
||||||
|
<h3>📘 Student Progress Report</h3>
|
||||||
|
<label for="reportUser">Select Student:</label>
|
||||||
|
<select id="reportUser" onchange="loadStudentReport(this.value)">
|
||||||
|
<option value="">-- Select --</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div id="reportContent" class="hidden">
|
||||||
|
<h4 id="reportTitle"></h4>
|
||||||
|
<p><strong>Last Score:</strong> <span id="reportScore"></span></p>
|
||||||
|
<p><strong>Words Attempted:</strong></p>
|
||||||
|
<ul id="reportWords"></ul>
|
||||||
|
<p><strong>Badges Earned:</strong></p>
|
||||||
|
<ul id="reportBadges"></ul>
|
||||||
|
|
||||||
|
<button onclick="window.print()">🖨️ Print Report</button>
|
||||||
|
<button onclick="copyReportToClipboard()">📋 Copy to Clipboard</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 👩🎓 Student Panel -->
|
<!-- 👩🎓 Student Panel -->
|
||||||
<div id="studentPanel" class="hidden">
|
<div id="studentPanel" class="hidden">
|
||||||
<div id="toast" class="toast">Welcome, student!</div>
|
<div id="toast" class="toast">Welcome, student!</div>
|
||||||
|
|||||||
@@ -205,6 +205,10 @@ function switchTab(targetId) {
|
|||||||
if (targetId === 'tabBadges') {
|
if (targetId === 'tabBadges') {
|
||||||
loadBadgeViewer();
|
loadBadgeViewer();
|
||||||
}
|
}
|
||||||
|
// Reports
|
||||||
|
if (targetId === 'tabReports') {
|
||||||
|
loadStudentNamesForReport();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async function loadUserDropdowns() {
|
async function loadUserDropdowns() {
|
||||||
try {
|
try {
|
||||||
@@ -322,4 +326,65 @@ function showUserBadges(username) {
|
|||||||
|
|
||||||
details.classList.remove("hidden");
|
details.classList.remove("hidden");
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
async function loadStudentNamesForReport() {
|
||||||
|
const res = await fetch('/getResults');
|
||||||
|
const data = await res.json();
|
||||||
|
const select = document.getElementById("reportUser");
|
||||||
|
|
||||||
|
select.innerHTML = `<option value="">-- Select --</option>`;
|
||||||
|
Object.keys(data).forEach(username => {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = username;
|
||||||
|
opt.textContent = username;
|
||||||
|
select.appendChild(opt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadStudentReport(username) {
|
||||||
|
if (!username) return;
|
||||||
|
|
||||||
|
const res1 = await fetch('/getResults');
|
||||||
|
const results = await res1.json();
|
||||||
|
const res2 = await fetch('/getBadges');
|
||||||
|
const badges = await res2.json();
|
||||||
|
|
||||||
|
const report = results[username];
|
||||||
|
const badgeList = badges[username] || [];
|
||||||
|
|
||||||
|
document.getElementById("reportTitle").textContent = `Report for ${username}`;
|
||||||
|
document.getElementById("reportScore").textContent = `${report.score}/${report.answers.length} correct`;
|
||||||
|
|
||||||
|
const wordList = document.getElementById("reportWords");
|
||||||
|
wordList.innerHTML = "";
|
||||||
|
report.answers.forEach(({ word, correct }) => {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.textContent = `${word} — ${correct ? '✅' : '❌'}`;
|
||||||
|
wordList.appendChild(li);
|
||||||
|
});
|
||||||
|
|
||||||
|
const badgeContainer = document.getElementById("reportBadges");
|
||||||
|
badgeContainer.innerHTML = "";
|
||||||
|
if (badgeList.length) {
|
||||||
|
badgeList.forEach(b => {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.textContent = `🏅 ${b}`;
|
||||||
|
badgeContainer.appendChild(li);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
badgeContainer.innerHTML = "<li><em>No badges earned yet.</em></li>";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("reportContent").classList.remove("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyReportToClipboard() {
|
||||||
|
const name = document.getElementById("reportTitle").textContent;
|
||||||
|
const score = document.getElementById("reportScore").textContent;
|
||||||
|
const words = Array.from(document.querySelectorAll("#reportWords li")).map(li => li.textContent).join("\n");
|
||||||
|
const badges = Array.from(document.querySelectorAll("#reportBadges li")).map(li => li.textContent).join("\n");
|
||||||
|
|
||||||
|
const summary = `${name}\nScore: ${score}\n\nWords:\n${words}\n\nBadges:\n${badges}`;
|
||||||
|
navigator.clipboard.writeText(summary);
|
||||||
|
alert("✅ Report copied to clipboard");
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user