adding results
This commit is contained in:
1 parent
49e2d58fae
commit
3e6c02e4d2
6 files changed
+139
-26
No files matched your search
+51
-26
@@ -30,10 +30,20 @@
|
|||||||
<button onclick="logoutUser()">Log Out</button>
|
<button onclick="logoutUser()">Log Out</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 👨🏫 Admin Panel -->
|
|
||||||
<div id="adminPanel" class="hidden">
|
<div id="adminPanel" class="hidden">
|
||||||
<h2>Add New User</h2>
|
<h2>👨🏫 Admin Panel</h2>
|
||||||
|
|
||||||
|
<!-- Tab Controls -->
|
||||||
|
<div id="adminTabs">
|
||||||
|
<button onclick="switchTab('tabUsers')" class="active">👤 Manage Users</button>
|
||||||
|
<button onclick="switchTab('tabWords')">📝 Word Lists</button>
|
||||||
|
<button onclick="switchTab('tabResults')">📊 Results</button>
|
||||||
|
<button onclick="switchTab('tabTheme')">🎨 Theme</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Manage Users -->
|
||||||
|
<div id="tabUsers" class="adminTab">
|
||||||
|
<h3>Add New User</h3>
|
||||||
<form onsubmit="event.preventDefault(); addNewUser();">
|
<form onsubmit="event.preventDefault(); addNewUser();">
|
||||||
<input type="text" id="newUsername" placeholder="Username" required />
|
<input type="text" id="newUsername" placeholder="Username" required />
|
||||||
<input type="password" id="newPassword" placeholder="Password" required />
|
<input type="password" id="newPassword" placeholder="Password" required />
|
||||||
@@ -44,37 +54,17 @@
|
|||||||
<button type="submit">Add User</button>
|
<button type="submit">Add User</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Manage Users -->
|
|
||||||
<h3>Delete Users</h3>
|
<h3>Delete Users</h3>
|
||||||
<select id="userDropdown" onchange="selectUserAction(this.value)">
|
<select id="userDropdown" onchange="selectUserAction(this.value)">
|
||||||
<option value="">-- Select a user --</option>
|
<option value="">-- Select a user --</option>
|
||||||
</select>
|
</select>
|
||||||
<!-- Edit words -->
|
</div>
|
||||||
|
|
||||||
|
<!-- Word Lists -->
|
||||||
|
<div id="tabWords" class="adminTab hidden">
|
||||||
<h3>Edit Word List for:</h3>
|
<h3>Edit Word List for:</h3>
|
||||||
<select id="wordUserSelect" class="word-user-dropdown" onchange="loadWordsForSelectedUser()">
|
<select id="wordUserSelect" class="word-user-dropdown" onchange="loadWordsForSelectedUser()">
|
||||||
<option value="">-- Select a user --</option>
|
<option value="">-- Select a user --</option>
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- View Word List by User -->
|
|
||||||
<h3>📋 View Word List by User:</h3>
|
|
||||||
<select id="viewUserSelect" class="word-user-dropdown" onchange="displayWordListForSelectedUser()">
|
|
||||||
<option value="">-- Select a user --</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<ul id="userWordListDisplay"></ul>
|
|
||||||
|
|
||||||
<!-- Theme -->
|
|
||||||
<div style="margin: 1em 0;">
|
|
||||||
<label for="themeSelect"><strong>Select Theme:</strong></label><br/>
|
|
||||||
<select id="themeSelect" onchange="changeTheme(this.value)">
|
|
||||||
<option value="playground">Playground</option>
|
|
||||||
<option value="chalkboard">Chalkboard</option>
|
|
||||||
<option value="galaxy">Galaxy</option>
|
|
||||||
<option value="nature">Nature</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Enter Spelling Words</h2>
|
<h2>Enter Spelling Words</h2>
|
||||||
<textarea id="wordInput" placeholder="Enter one word per line..."></textarea><br/>
|
<textarea id="wordInput" placeholder="Enter one word per line..."></textarea><br/>
|
||||||
<button onclick="saveWords()">Save Word List</button>
|
<button onclick="saveWords()">Save Word List</button>
|
||||||
@@ -84,6 +74,41 @@
|
|||||||
<input type="file" accept=".txt,.csv" onchange="handleFileUpload(event)" />
|
<input type="file" accept=".txt,.csv" onchange="handleFileUpload(event)" />
|
||||||
<p><strong>Current Word List:</strong></p>
|
<p><strong>Current Word List:</strong></p>
|
||||||
<ul id="wordListDisplay"></ul>
|
<ul id="wordListDisplay"></ul>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<h3>📋 View Word List by User:</h3>
|
||||||
|
<select id="viewUserSelect" class="word-user-dropdown" onchange="displayWordListForSelectedUser()">
|
||||||
|
<option value="">-- Select a user --</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<ul id="userWordListDisplay"></ul>
|
||||||
|
|
||||||
|
<h3>Enter Spelling Words</h3>
|
||||||
|
<textarea id="wordInput" placeholder="Enter one word per line..."></textarea><br/>
|
||||||
|
<button onclick="saveWords()">Save Word List</button>
|
||||||
|
<button onclick="clearWords()">Clear Saved Words</button>
|
||||||
|
|
||||||
|
<h3>Or Upload a Word File</h3>
|
||||||
|
<input type="file" accept=".txt,.csv" onchange="handleFileUpload(event)" />
|
||||||
|
<ul id="wordListDisplay"></ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Student Results -->
|
||||||
|
<div id="tabResults" class="adminTab hidden">
|
||||||
|
<h3>🧾 Student Results Overview</h3>
|
||||||
|
<button onclick="loadStudentResults()">Refresh Results</button>
|
||||||
|
<ul id="resultsList"></ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Theme Selection -->
|
||||||
|
<div id="tabTheme" class="adminTab hidden">
|
||||||
|
<h3>🎨 Select Theme</h3>
|
||||||
|
<select id="themeSelect" onchange="changeTheme(this.value)">
|
||||||
|
<option value="playground">Playground</option>
|
||||||
|
<option value="chalkboard">Chalkboard</option>
|
||||||
|
<option value="galaxy">Galaxy</option>
|
||||||
|
<option value="nature">Nature</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 👩🎓 Student Panel -->
|
<!-- 👩🎓 Student Panel -->
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"student1": { "score": 8, "completed": true, "answers": ["cat", "dog", "fish"] },
|
||||||
|
"nate": { "score": 10, "completed": true, "answers": ["grace", "truth", "peace"] }
|
||||||
|
}
|
||||||
@@ -440,3 +440,45 @@ async function displayWordListForSelectedUser() {
|
|||||||
console.error("Failed to load word list for user:", username, err)
|
console.error("Failed to load word list for user:", username, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function loadStudentResults() {
|
||||||
|
const list = document.getElementById("resultsList")
|
||||||
|
list.innerHTML = ''
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/getResults')
|
||||||
|
const results = await res.json()
|
||||||
|
|
||||||
|
if (!Object.keys(results).length) {
|
||||||
|
list.innerHTML = '<li><em>No results available yet.</em></li>'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [username, result] of Object.entries(results)) {
|
||||||
|
const li = document.createElement('li')
|
||||||
|
li.innerHTML = `<strong>${username}</strong> — Score: ${result.score}, Completed: ${result.completed ? '✅' : '❌'}<br>
|
||||||
|
Answers: ${result.answers.join(', ')}`
|
||||||
|
list.appendChild(li)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("🔴 Failed to load results:", err)
|
||||||
|
list.innerHTML = '<li style="color:red">Error loading results.</li>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function switchTab(targetId) {
|
||||||
|
// Hide all tabs
|
||||||
|
document.querySelectorAll('.adminTab').forEach(tab => tab.classList.add('hidden'))
|
||||||
|
|
||||||
|
// Remove active class from buttons
|
||||||
|
document.querySelectorAll('#adminTabs button').forEach(btn => btn.classList.remove('active'))
|
||||||
|
|
||||||
|
// Show the selected tab
|
||||||
|
document.getElementById(targetId).classList.remove('hidden')
|
||||||
|
|
||||||
|
// Highlight active tab button
|
||||||
|
const buttons = document.querySelectorAll('#adminTabs button')
|
||||||
|
buttons.forEach(btn => {
|
||||||
|
if (btn.getAttribute('onclick')?.includes(targetId)) {
|
||||||
|
btn.classList.add('active')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -123,3 +123,36 @@ body.nature button {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
#adminTabs {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
#adminTabs button {
|
||||||
|
margin-right: 8px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-bottom: none;
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s, color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#adminTabs button:hover {
|
||||||
|
background-color: #e0f2ff;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#adminTabs button.active {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #000;
|
||||||
|
border-bottom: 2px solid #fff;
|
||||||
|
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.adminTab {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.adminTab:not(.hidden) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -8,5 +8,10 @@
|
|||||||
"username": "student1",
|
"username": "student1",
|
||||||
"hash": "8d969eef6ecad3c29a3a629280e686cf",
|
"hash": "8d969eef6ecad3c29a3a629280e686cf",
|
||||||
"role": "student"
|
"role": "student"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "nate",
|
||||||
|
"hash": "5a2a558c78d3717db731600c4f354fa1d9c84b556f108091a891f444f1bdec40",
|
||||||
|
"role": "student"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -49,5 +49,9 @@ app.post('/saveWordList', (req, res) => {
|
|||||||
fs.writeFileSync('public/wordlists.json', JSON.stringify(data, null, 2))
|
fs.writeFileSync('public/wordlists.json', JSON.stringify(data, null, 2))
|
||||||
res.send(`✅ Word list saved for ${username}`)
|
res.send(`✅ Word list saved for ${username}`)
|
||||||
})
|
})
|
||||||
|
app.get('/getResults', (req, res) => {
|
||||||
|
const results = JSON.parse(fs.readFileSync('public/results.json', 'utf-8'))
|
||||||
|
res.json(results)
|
||||||
|
})
|
||||||
|
|
||||||
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`))
|
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`))
|
||||||
Reference in new issue
Block a user