let users = [] // ๐ Load users from server-side users.json async function loadUsers() { try { const res = await fetch("users.json") users = await res.json() } catch (e) { console.error("Failed to load users.json:", e) users = [] } } // ๐ Password hashing function hashPassword(password) { const shaObj = new jsSHA("SHA-256", "TEXT") shaObj.update(password) return shaObj.getHash("HEX") } // ๐ค Login async function verifyLogin() { const uname = document.getElementById('username').value.trim() const pw = document.getElementById('password').value const hash = hashPassword(pw) const msg = document.getElementById('loginMessage') const user = users.find(u => u.username === uname && u.hash === hash) if (user) { localStorage.setItem('loggedInUser', JSON.stringify(user)) msg.textContent = '' setupSession(user) await showAdmin() } else { msg.textContent = "Invalid username or password." } } // ๐ง On load window.addEventListener('DOMContentLoaded', async () => { await loadUsers() displayUserDropdown() const savedTheme = localStorage.getItem('theme') || 'playground' document.body.className = savedTheme const dropdown = document.getElementById('themeSelect') if (dropdown) dropdown.value = savedTheme const savedUser = localStorage.getItem('loggedInUser') if (savedUser) setupSession(JSON.parse(savedUser)) }) // ๐งโ๐ซ Admin setup async function setupSession(user) { // ๐ Hide everything first for clean slate document.getElementById('loginPanel').classList.add('hidden') document.getElementById('adminPanel').classList.add('hidden') document.getElementById('studentPanel').classList.add('hidden') // ๐ Show navigation and user info document.getElementById('nav').classList.remove('hidden') document.getElementById('userInfo').textContent = `${user.username} (${user.role})` // ๐จ Role-colored banner setup const roleBanner = document.getElementById('roleBanner') roleBanner.classList.remove('hidden', 'admin', 'student') roleBanner.classList.add(user.role) roleBanner.textContent = user.role === "admin" ? "๐จโ๐ซ Admin Access Enabled" : "๐ Student Mode Active" // ๐ Hide/show Student Panel button appropriately const studentBtn = document.getElementById('studentBtn') if (user.role === "admin") { studentBtn.classList.remove('hidden') document.getElementById('adminBtn').classList.remove('hidden') console.log("๐ Logged in as Admin") await showAdmin() } else if (user.role === "student") { studentBtn.classList.add('hidden') document.getElementById('adminBtn').classList.add('hidden') console.log("๐ Logged in as Student") showStudent() } else { console.warn("โ Unknown role:", user.role) logoutUser() alert("Unknown role detected. Logging out for security.") return } // ๐ฃ Toast message showToast(`Welcome, ${user.role}!`) } function logoutUser() { // Clear stored user session localStorage.removeItem('loggedInUser') // ๐ Reset all visible panels document.getElementById('adminPanel').classList.add('hidden') document.getElementById('studentPanel').classList.add('hidden') document.getElementById('nav').classList.add('hidden') document.getElementById('loginPanel').classList.remove('hidden') document.getElementById('username').value = '' document.getElementById('password').value = '' // ๐งผ Reset role banner styling and content const roleBanner = document.getElementById('roleBanner') roleBanner.classList.add('hidden') roleBanner.classList.remove('admin', 'student') roleBanner.textContent = '' // Optional: reset login message (if present) const loginMessage = document.getElementById('loginMessage') if (loginMessage) loginMessage.textContent = '' } async function showAdmin() { const user = JSON.parse(localStorage.getItem('loggedInUser')) if (!user || user.role !== "admin") { console.warn("โ Access denied: not an admin") return } document.getElementById('adminPanel').classList.remove('hidden') document.getElementById('studentPanel').classList.add('hidden') await loadWords() displayWordList() await loadUsers() displayUserDropdown() populateWordUserDropdown() } // โ Add User async function addNewUser() { const username = document.getElementById("newUsername").value.trim() const password = document.getElementById("newPassword").value const role = document.getElementById("newRole").value const msg = document.getElementById("userAddMessage") const hashPreview = document.getElementById("hashPreview") if (!username || !password) { msg.textContent = "Please fill out all fields." return } const hash = hashPassword(password) // Live hash preview (optional visual confirmation for admin) if (hashPreview) { hashPreview.textContent = hash } try { await saveUserToServer(username, hash, role) msg.textContent = `โ User "${username}" added to server.` // Clear fields after success document.getElementById("newUsername").value = '' document.getElementById("newPassword").value = '' if (hashPreview) hashPreview.textContent = '[auto]' await loadUsers() displayUserDropdown() } catch (e) { msg.textContent = "โ Failed to add user." console.error("Add user error:", e) } } async function saveUserToServer(username, hash, role) { const res = await fetch('/addUser', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, hash, role }) }) const msg = await res.text() alert(msg) } // ๐ User deletion function displayUserDropdown() { const dropdown = document.getElementById("userDropdown") dropdown.innerHTML = `` users.forEach(user => { dropdown.innerHTML += `` }) } function selectUserAction(username) { if (!username) return const confirmDelete = confirm(`Are you sure you want to delete user "${username}"?`) if (!confirmDelete) { document.getElementById("userDropdown").value = "" return } fetch("/deleteUser", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username }) }) .then(res => res.text()) .then(msg => { alert(msg) loadUsers().then(displayUserDropdown) }) } // ๐จ Theme function changeTheme(themeName) { document.body.className = themeName localStorage.setItem('theme', themeName) } // ๐ Word list function saveWords() { const text = document.getElementById('wordInput').value.trim() allWords = text.split('\n').map(w => w.trim()).filter(Boolean) localStorage.setItem('spellingWords', JSON.stringify(allWords)) displayWordList() alert("Word list saved!") } function clearWords() { localStorage.removeItem('spellingWords') allWords = [] displayWordList() alert("Saved words cleared.") } function displayWordList() { const ul = document.getElementById('wordListDisplay') ul.innerHTML = allWords.map(word => `
You got ${correct} out of ${words.length} correct (${Math.round((correct / words.length) * 100)}%)