From d6f5a70e52dd737a88953fc92f2691fdb9dba9fa Mon Sep 17 00:00:00 2001 From: "nate@necloud.us" Date: Mon, 28 Jul 2025 08:40:04 -0400 Subject: [PATCH] results --- public/js/admin.js | 10 ++++++++-- public/js/typing.js | 35 ++++++++++++++++++++++++++++++++--- server.js | 24 ++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/public/js/admin.js b/public/js/admin.js index 8e33bf3..fbc2050 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -390,7 +390,6 @@ window.loadStudentResults = async function() { userResults.forEach((result, index) => { const li = document.createElement("li"); let answersHTML = ''; - // Check if result and answers exist and are valid if (result && result.answers && Array.isArray(result.answers)) { result.answers.forEach(entry => { @@ -402,8 +401,15 @@ window.loadStudentResults = async function() { } const timestamp = result.timestamp ? new Date(result.timestamp).toLocaleString() : 'Unknown time'; + // Label result type + let typeLabel = ''; + if (result.type === 'typing') { + typeLabel = '[Typing Practice] '; + } else { + typeLabel = '[Game] '; + } li.innerHTML = ` - ${username} (Session ${index + 1}) — Score: ${result?.score || 'N/A'}, Completed: ${result?.completed ? '✅' : '❌'}
+ ${typeLabel}${username} (Session ${index + 1}) — Score: ${result?.score || 'N/A'}, Completed: ${result?.completed ? '✅' : '❌'}
Date: ${timestamp}
Answers:
${answersHTML}
diff --git a/public/js/typing.js b/public/js/typing.js index 2030662..3fc4f17 100644 --- a/public/js/typing.js +++ b/public/js/typing.js @@ -40,7 +40,11 @@ window.startTypingPractice = async function() { } } -window.showNextWord = function() { + +// Track answers for results +typingState.answers = []; + +window.showNextWord = async function() { const promptEl = document.getElementById('typingPrompt'); const inputEl = document.getElementById('typingInput'); if (!promptEl || !inputEl) return; @@ -48,6 +52,8 @@ window.showNextWord = function() { if (!typingState.words.length) { promptEl.textContent = '🎉 Practice complete!'; inputEl.disabled = true; + // Save results to backend + await saveTypingPracticeResults(); return; } @@ -64,13 +70,36 @@ window.showNextWord = function() { inputEl.focus(); } +async function saveTypingPracticeResults() { + const user = JSON.parse(localStorage.getItem('loggedInUser')); + if (!user) return; + const result = { + score: typingState.answers.filter(a => a.correct).length, + completed: true, + answers: typingState.answers + }; + try { + await fetch('/saveTypingResults', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username: user.username, result }) + }); + console.log('Typing practice results saved'); + } catch (e) { + console.error('Failed to save typing results', e); + } +} + window.submitTyping = function() { const input = document.getElementById('typingInput')?.value.trim() || ''; const feedback = document.getElementById('typingFeedback'); if (!feedback) return; - - if (input.toLowerCase() === typingState.currentWord.toLowerCase()) { + + const correct = input.toLowerCase() === typingState.currentWord.toLowerCase(); + typingState.answers.push({ word: typingState.currentWord, input, correct }); + + if (correct) { feedback.textContent = '✅ Correct!'; feedback.style.color = 'green'; typingState.words.shift(); diff --git a/server.js b/server.js index d4c1cf8..6776c48 100644 --- a/server.js +++ b/server.js @@ -407,6 +407,30 @@ app.post('/saveResults', (req, res) => { }); // 👥 Get users +// --- Typing Practice Results --- +// Save typing practice results for a user +app.post('/saveTypingResults', (req, res) => { + const { username, result } = req.body; + if ( + typeof username !== 'string' || + typeof result !== 'object' || + typeof result.score !== 'number' || + typeof result.completed !== 'boolean' || + !Array.isArray(result.answers) + ) return res.status(400).send("Invalid result format"); + + const resultsPath = path.join(DATA_DIR, files.results); + const allResults = readJsonSafe(resultsPath); + if (!allResults[username]) allResults[username] = []; + + allResults[username].push({ + ...result, + timestamp: new Date().toISOString(), + type: 'typing' // Mark as typing practice result + }); + fs.writeFileSync(resultsPath, JSON.stringify(allResults, null, 2)); + res.send(`✅ Typing results archived for ${username}`); +}); app.get('/getUsers', (req, res) => { const users = readJsonSafe(path.join(DATA_DIR, files.users), []); res.json(users);