JIT
Fix and Functionalize Learning Management System Code
fix everything and make it proper and functional learning management system that is connected in every dashboard on this code: login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login</title> <link rel="stylesheet" href="login.css"> </head> <body> <!-- Login Form --> <div class="login-container" id="login-container"> <h2>Login</h2> <input type="text" id="username" placeholder="Enter Username"> <input type="password" id="password" placeholder="Enter Password"> <select id="role"> <option value="">Select Role</option> <option value="teacher">Teacher</option> <option value="student">Junior High School Student</option> <option value="parent">Parent</option> </select> <!-- Container for Teacher ID --> <div id="loginTeacherIdContainer" class="hidden"> <input type="text" id="loginTeacherId" placeholder="Enter Teacher ID Number"> </div> <!-- Container for Student ID --> <div id="loginStudentIdContainer" class="hidden"> <input type="text" id="loginStudentId" placeholder="Enter Student ID Number"> </div> <button onclick="login()">Login</button> <p id="errorMessage" class="error-message"></p> <p>Don't have an account? <a href="#" onclick="showSignup()">Sign up</a></p> </div> <!-- Sign Up Form --> <div class="signup-container hidden" id="signup-container"> <h2>Sign Up</h2> <input type="text" id="newUsername" placeholder="Choose a Username"> <input type="password" id="newPassword" placeholder="Choose a Password"> <select id="newRole"> <option value="">Select Role</option> <option value="teacher">Teacher</option> <option value="student">Junior High School Student</option> <option value="parent">Parent</option> </select> <!-- Container for Teacher ID --> <div id="signupTeacherIdContainer" class="hidden"> <input type="text" id="signupTeacherId" placeholder="Enter Teacher ID Number"> </div> <!-- Container for Student Info (Full Name and ID) --> <div id="signupStudentInfoContainer" class="hidden"> <input type="text" id="fullName" placeholder="Enter Full Name"> <input type="text" id="signupStudentId" placeholder="Enter Student ID Number"> </div> <button onclick="signup()">Sign Up</button> <p id="signupMessage" class="signup-message"></p> <p>Already have an account? <a href="#" onclick="showLogin()">Log in</a></p> </div> <script src="login.js"></script> </body> </html> login.css * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #a2c2e2, #f4f4f4); display: flex; justify-content: center; align-items: center; min-height: 100vh; /* Use min-height for pages that might grow */ padding: 20px; } .container, /* Generic container for homepage/dashboards */ .login-container, .signup-container { background: #fff; width: 100%; max-width: 450px; /* Slightly wider for homepage/dashboards */ padding: 30px; border-radius: 12px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); text-align: center; } h1, h2 { /* Style h1 for homepage/dashboards */ color: #333; margin-bottom: 20px; font-size: 24px; font-weight: bold; } input, select, button { width: 100%; padding: 15px; margin: 10px 0; border-radius: 8px; border: 1px solid #ddd; font-size: 16px; outline: none; transition: all 0.3s ease; } input:focus, select:focus, button:focus { border-color: #28a745; box-shadow: 0 0 8px rgba(40, 167, 69, 0.3); } button { background: #28a745; color: white; border: none; cursor: pointer; font-weight: bold; transition: background 0.3s ease; } button:hover { background: #218838; } .hidden { display: none; } /* Style for the specific ID containers to ensure consistent margin */ #loginTeacherIdContainer input, #loginStudentIdContainer input, #signupTeacherIdContainer input, #signupStudentInfoContainer input { margin-top: 0; /* Inputs inside these divs already have margin */ } /* Add margin between inputs within the student info container */ #signupStudentInfoContainer input#fullName { margin-bottom: 10px; } .error-message, .signup-message { color: red; font-size: 14px; margin-top: 10px; min-height: 1.2em; /* Reserve space */ } p { font-size: 14px; color: #666; margin-top: 15px; } p a { color: #28a745; text-decoration: none; } p a:hover { text-decoration: underline; } /* Homepage/Dashboard specific styles */ .welcome-message { font-size: 18px; margin-bottom: 25px; color: #555; } login.js // Retrieve users from localStorage function getUsers() { return JSON.parse(localStorage.getItem("users")) || {}; } // Save users to localStorage function saveUsers(users) { localStorage.setItem("users", JSON.stringify(users)); } function login() { const username = document.getElementById("username").value.trim(); const password = document.getElementById("password").value.trim(); const role = document.getElementById("role").value; const errorMessage = document.getElementById("errorMessage"); errorMessage.textContent = ''; // Clear previous error // Get potential ID values const teacherId = document.getElementById("loginTeacherId")?.value.trim(); const studentId = document.getElementById("loginStudentId")?.value.trim(); if (!username || !password || !role) { errorMessage.textContent = "Please fill in username, password, and select a role."; return; } // Role-specific ID validation if (role === 'teacher' && !teacherId) { errorMessage.textContent = "Please enter your Teacher ID Number."; return; } if (role === 'student' && !studentId) { errorMessage.textContent = "Please enter your Student ID Number."; return; } const users = getUsers(); const userData = users[username]; // Check if user exists and credentials match let credentialsMatch = userData && userData.password === password && userData.role === role; // Check ID if applicable if (credentialsMatch && role === 'teacher') { credentialsMatch = userData.teacherId === teacherId; } if (credentialsMatch && role === 'student') { credentialsMatch = userData.studentId === studentId; } if (credentialsMatch) { // Store user info in sessionStorage sessionStorage.setItem('loggedInUsername', username); sessionStorage.setItem('loggedInRole', role); // Store full name if user is a student if (role === 'student' && userData.fullName) { sessionStorage.setItem('loggedInFullName', userData.fullName); } // Optionally store ID if needed later if (role === 'teacher') sessionStorage.setItem('loggedInTeacherId', teacherId); if (role === 'student') sessionStorage.setItem('loggedInStudentId', studentId); // Redirect to the homepage (assuming homepage.html exists) // Make sure you have a homepage.html file or change this destination window.location.href = "homepage.html"; } else { errorMessage.textContent = "Incorrect username, password, role, or ID. Please try again."; } } function signup() { const newUsername = document.getElementById("newUsername").value.trim(); const newPassword = document.getElementById("newPassword").value.trim(); const newRole = document.getElementById("newRole").value; const signupMessage = document.getElementById("signupMessage"); signupMessage.textContent = ''; // Clear previous message // Get potential ID and name values const teacherId = document.getElementById("signupTeacherId")?.value.trim(); const studentId = document.getElementById("signupStudentId")?.value.trim(); const fullName = document.getElementById("fullName")?.value.trim(); if (!newUsername || !newPassword || !newRole) { signupMessage.textContent = "Please fill in username, password, and select a role."; return; } // Basic password validation if (newPassword.length < 4) { signupMessage.textContent = "Password must be at least 4 characters long."; return; } // Role-specific field validation if (newRole === 'teacher' && !teacherId) { signupMessage.textContent = "Teacher ID Number is required for teachers."; return; } if (newRole === 'student' && (!fullName || !studentId)) { signupMessage.textContent = "Full Name and Student ID Number are required for students."; return; } const users = getUsers(); if (users[newUsername]) { signupMessage.textContent = "Username already exists. Please choose a different one."; return; } // Store new user in localStorage const newUser = { password: newPassword, role: newRole }; if (newRole === 'teacher') { newUser.teacherId = teacherId; } if (newRole === 'student') { newUser.fullName = fullName; newUser.studentId = studentId; } users[newUsername] = newUser; saveUsers(users); alert(`Account created successfully for ${newUsername}! Please log in.`); // Switch back to login form showLogin(); } function showSignup() { document.getElementById("signup-container").classList.remove("hidden"); document.getElementById("login-container").classList.add("hidden"); document.getElementById("errorMessage").textContent = ''; document.getElementById("signupMessage").textContent = ''; // Reset signup form fields document.getElementById("newUsername").value = ''; document.getElementById("newPassword").value = ''; document.getElementById("newRole").value = ''; document.getElementById("signupTeacherId").value = ''; document.getElementById("fullName").value = ''; document.getElementById("signupStudentId").value = ''; // Hide role-specific fields initially document.getElementById("signupTeacherIdContainer").classList.add("hidden"); document.getElementById("signupStudentInfoContainer").classList.add("hidden"); } function showLogin() { document.getElementById("login-container").classList.remove("hidden"); document.getElementById("signup-container").classList.add("hidden"); document.getElementById("errorMessage").textContent = ''; document.getElementById("signupMessage").textContent = ''; // Reset login form fields document.getElementById("username").value = ''; document.getElementById("password").value = ''; document.getElementById("role").value = ''; document.getElementById("loginTeacherId").value = ''; document.getElementById("loginStudentId").value = ''; // Hide role-specific fields initially document.getElementById("loginTeacherIdContainer").classList.add("hidden"); document.getElementById("loginStudentIdContainer").classList.add("hidden"); } // Event listener for role change in LOGIN form document.getElementById('role')?.addEventListener('change', function() { const teacherIdContainer = document.getElementById('loginTeacherIdContainer'); const studentIdContainer = document.getElementById('loginStudentIdContainer'); const teacherIdInput = document.getElementById('loginTeacherId'); const studentIdInput = document.getElementById('loginStudentId'); // Hide both first teacherIdContainer?.classList.add('hidden'); studentIdContainer?.classList.add('hidden'); if(teacherIdInput) teacherIdInput.value = ''; // Clear value when hidden if(studentIdInput) studentIdInput.value = ''; // Clear value when hidden if (this.value === 'teacher') { teacherIdContainer?.classList.remove('hidden'); } else if (this.value === 'student') { studentIdContainer?.classList.remove('hidden'); } }); // Event listener for role change in SIGNUP form document.getElementById('newRole')?.addEventListener('change', function() { const teacherIdContainer = document.getElementById('signupTeacherIdContainer'); const studentInfoContainer = document.getElementById('signupStudentInfoContainer'); const teacherIdInput = document.getElementById('signupTeacherId'); const studentIdInput = document.getElementById('signupStudentId'); const fullNameInput = document.getElementById('fullName'); // Hide all role-specific containers first teacherIdContainer?.classList.add('hidden'); studentInfoContainer?.classList.add('hidden'); // Clear values when hidden if(teacherIdInput) teacherIdInput.value = ''; if(studentIdInput) studentIdInput.value = ''; if(fullNameInput) fullNameInput.value = ''; if (this.value === 'teacher') { teacherIdContainer?.classList.remove('hidden'); } else if (this.value === 'student') { studentInfoContainer?.classList.remove('hidden'); } }); // Clear session storage on login page load and ensure correct form is shown document.addEventListener('DOMContentLoaded', () => { // Only run login page specific logic if login container exists if (document.getElementById('login-container')) { sessionStorage.clear(); // Clear all session storage on login page load showLogin(); // Ensure login form is shown by default and fields are reset/hidden } }); homepage.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Welcome</title> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #e2f0d9, #f4f4f4); /* Light green gradient */ display: flex; justify-content: center; align-items: center; height: 100vh; padding: 20px; text-align: center; color: #333; margin: 0; } .welcome-container { background: #fff; padding: 40px; border-radius: 12px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); max-width: 500px; width: 100%; } h1 { color: #28a745; /* Green color */ margin-bottom: 15px; font-size: 28px; } p { font-size: 18px; margin-bottom: 30px; line-height: 1.6; } .dashboard-button { display: inline-block; padding: 15px 30px; background: #28a745; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 18px; font-weight: bold; text-decoration: none; transition: background 0.3s ease; } .dashboard-button:hover { background: #218838; } /* Removed .logout-button styles */ </style> </head> <body> <div class="welcome-container"> <h1 id="welcome-message">Welcome!</h1> <p>You have successfully logged in. Click the button below to proceed to your dashboard.</p> <button id="dashboard-link" class="dashboard-button">Go to Dashboard</button> <!-- Removed Logout Button --> </div> <script> document.addEventListener('DOMContentLoaded', () => { const username = sessionStorage.getItem('loggedInUsername'); const role = sessionStorage.getItem('loggedInRole'); const welcomeMessage = document.getElementById('welcome-message'); const dashboardLink = document.getElementById('dashboard-link'); // Removed reference to logoutBtn // If no user info found, redirect to login if (!username || !role) { alert('You need to log in first.'); window.location.href = 'login.html'; return; } // Personalize welcome message welcomeMessage.textContent = `Welcome, ${username}!`; // Determine dashboard URL let dashboardUrl = ''; if (role === 'teacher') { dashboardUrl = 'teacher.html'; } else if (role === 'student') { dashboardUrl = 'student.html'; } else if (role === 'parent') { dashboardUrl = 'parent.html'; } else { // Fallback if role is unexpected (redirect to login) alert('Invalid user role detected.'); sessionStorage.removeItem('loggedInUsername'); // Clear session sessionStorage.removeItem('loggedInRole'); window.location.href = 'login.html'; return; } // Set button click action dashboardLink.onclick = () => { window.location.href = dashboardUrl; }; // Removed logoutBtn.onclick assignment }); // Removed logout function </script> </body> </html> teachr.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Teacher Dashboard</title> <link rel="stylesheet" href="teacher.css"> </head> <body> <div class="navbar"> <h1>Teacher Dashboard</h1> </div> <div class="container"> <div class="button-container"> <button class="btn" id="createLessonBtn">Create Lesson</button> <button class="btn" id="createQuizBtn">Make Quiz</button> <button class="btn" id="manageScoresBtn">Manage Scores & Grades</button> <button class="btn" id="deleteLessonBtn">Delete Lesson</button> <button class="btn" id="deleteQuizBtn">Delete Quiz</button> <!-- Delete Quiz Button Re-added --> </div> <h3>Created Lessons</h3> <div id="createdLessons"></div> <h3>Created Quizzes</h3> <div id="createdQuizzes"></div> </div> <!-- Lesson Modal (Create/Edit) --> <div id="lessonModal" class="modal"> <div class="modal-content"> <span class="close" data-modal-id="lessonModal">&times;</span> <h2 id="lessonModalTitle">Create Lesson</h2> <form id="lessonForm"> <input type="hidden" id="editLessonIndex" value="-1"> <label for="lessonTitle">Lesson Title:</label> <input type="text" id="lessonTitle" name="lessonTitle" required><br><br> <label for="lessonContent">Lesson Content:</label> <textarea id="lessonContent" name="lessonContent" rows="4" required></textarea><br><br> <button type="submit" id="lessonSubmitBtn" class="btn">Create Lesson</button> </form> </div> </div> <!-- Quiz Modal (Create/Edit) --> <div id="quizModal" class="modal"> <div class="modal-content large"> <span class="close" data-modal-id="quizModal">&times;</span> <h2 id="quizModalTitle">Create Quiz</h2> <form id="quizForm"> <input type="hidden" id="editQuizIndex" value="-1"> <label for="quizType">Quiz Type:</label> <select id="quizType" name="quizType" required> <option value="multiple-choice">Multiple Choice</option> <option value="identification">Identification</option> </select><br><br> <label for="quizTitle">Quiz Title:</label> <input type="text" id="quizTitle" name="quizTitle" required><br><br> <div id="questionsContainer"></div> <button type="button" class="btn" id="addQuestionBtn">Add Question</button><br><br> <button type="submit" id="quizSubmitBtn" class="btn">Create Quiz</button> </form> </div> </div> <!-- Delete Modal (Handles both Lessons and Quizzes) --> <div id="deleteModal" class="modal"> <div class="modal-content"> <span class="close" data-modal-id="deleteModal">&times;</span> <h2>Delete Item</h2> <!-- Generic Title --> <label for="deleteType">Item Type:</label> <!-- Generic Label --> <select id="deleteType"> <!-- Type Select Re-added --> <option value="lesson">Lesson</option> <option value="quiz">Quiz</option> </select><br><br> <label for="deleteChoice">Select Item to Delete:</label> <!-- Generic Label --> <select id="deleteChoice"></select><br><br> <button id="deleteBtn" class="btn delete">Delete</button> </div> </div> <!-- Manage Scores Modal --> <div id="manageScoresModal" class="modal"> <div class="modal-content large"> <span class="close" data-modal-id="manageScoresModal">&times;</span> <h2>Manage Scores and Grades</h2> <div class="manage-scores-container"> <label for="quizSelectForScores">Select Quiz:</label> <select id="quizSelectForScores"> <option value="">-- Select a Quiz --</option> <!-- Options populated by JS --> </select> <div id="studentScoresDisplay" class="scores-display-area"> <p class="no-scores-message">Select a quiz to view student scores.</p> <!-- Table will be inserted here by JS --> </div> </div> </div> </div> <!-- Performance Analytics Button --> <button id="analyticsBtn" class="analytics-btn">View Performance & Analytics</button> <!-- Performance Analytics Fullscreen Modal --> <div id="analyticsModal" class="modal fullscreen"> <div class="modal-content"> <h2>Teacher Performance & Analytics</h2> <div class="analytics-section"> <h3>Overview</h3> <p><strong>Lessons Created:</strong> <span id="lessonCount">0</span></p> <p><strong>Quizzes Created:</strong> <span id="quizCount">0</span></p> </div> <div class="analytics-section"> <h3>Class Performance (Example)</h3> <p>Average Quiz Score: <span id="averageQuizScore">N/A</span></p> </div> <div class="modal-navigation"> <button id="modalDashboardBtn" class="modal-nav-btn dashboard">Back to Dashboard</button> <button id="modalHomeBtn" class="modal-nav-btn home">Homepage</button> <button id="modalLogoutBtn" class="modal-nav-btn logout">Logout</button> </div> </div> </div> <script src="teacher.js"></script> </body> </html> teacher.css body { font-family: Arial, sans-serif; background-color: #f2f2f2; padding: 0 20px 80px 20px; /* Remove top padding, ensure bottom padding for fixed button */ margin: 0; line-height: 1.6; } /* Prevent body scroll when fullscreen modal is open */ body.modal-open { overflow: hidden; } .navbar { background-color: #4CAF50; color: white; padding: 15px 20px; /* Slightly more padding */ margin-bottom: 25px; /* More space */ border-radius: 0 0 5px 5px; /* Rounded bottom corners */ box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .navbar h1 { margin: 0; text-align: center; font-size: 1.8em; } .container { background-color: #fff; padding: 25px; border-radius: 8px; /* More rounded */ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); max-width: 1000px; /* Wider container */ margin: 0 auto 20px auto; /* Center container, reduce bottom margin */ } .hidden { display: none; } /* --- Standard Modal Styles --- */ .modal:not(.fullscreen) { /* Apply only to non-fullscreen modals */ display: none; position: fixed; z-index: 100; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0, 0, 0, 0.5); /* Darker overlay */ padding-top: 50px; } .modal:not(.fullscreen) .modal-content { background-color: #fff; margin: 3% auto; /* Adjust vertical margin */ padding: 25px 30px; /* More padding */ border: 1px solid #ccc; border-radius: 8px; width: 90%; max-width: 650px; /* Default max-width */ box-shadow: 0 5px 15px rgba(0,0,0,0.2); position: relative; /* For close button */ animation-name: animatetop; animation-duration: 0.4s; } /* Larger modal variant */ .modal:not(.fullscreen) .modal-content.large { max-width: 850px; } @keyframes animatetop { from {top: -300px; opacity: 0} to {top: 0; opacity: 1} } .close { color: #aaa; position: absolute; /* Position relative to modal-content */ top: 10px; right: 15px; font-size: 30px; font-weight: bold; line-height: 1; } .close:hover, .close:focus { color: black; text-decoration: none; cursor: pointer; } /* --- Fullscreen Modal Styles --- */ .modal.fullscreen { display: none; position: fixed; z-index: 1001; left: 0; top: 0; width: 100%; height: 100%; overflow: hidden; background-color: #f8f9fa; /* Light background */ } .modal.fullscreen .modal-content { background-color: transparent; margin: 0; padding: 40px; /* More padding */ border: none; width: 100%; height: 100%; max-width: none; border-radius: 0; box-shadow: none; position: relative; overflow-y: auto; box-sizing: border-box; } .modal.fullscreen h2 { text-align: center; color: #6f42c1; /* Keep purple for analytics title */ margin-top: 10px; margin-bottom: 40px; /* More space */ font-size: 2em; /* Larger title */ border-bottom: none; /* Remove border */ } .modal.fullscreen .analytics-section { margin-bottom: 30px; padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px; background-color: #fff; /* White background for sections */ max-width: 900px; margin-left: auto; margin-right: auto; } .modal.fullscreen .analytics-section:last-of-type { border-bottom: 1px solid #e0e0e0; /* Keep border */ } .modal.fullscreen .analytics-section h3 { color: #555; margin-top: 0; margin-bottom: 15px; font-size: 1.4em; border-bottom: 1px solid #eee; padding-bottom: 10px; } .modal.fullscreen .analytics-section p { font-size: 1.1em; margin-bottom: 10px; } .modal.fullscreen .analytics-section span { font-weight: normal; color: #333; } /* Styles for Navigation Buttons inside Fullscreen Modal */ .modal.fullscreen .modal-navigation { margin-top: 40px; padding-top: 30px; border-top: 1px solid #ccc; text-align: center; display: flex; justify-content: center; gap: 25px; max-width: 900px; margin-left: auto; margin-right: auto; } .modal.fullscreen .modal-nav-btn { padding: 12px 30px; border: none; border-radius: 6px; cursor: pointer; font-size: 1.1em; font-weight: bold; transition: background-color 0.3s ease, transform 0.2s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .modal.fullscreen .modal-nav-btn.dashboard { background-color: #ffc107; color: #333; } .modal.fullscreen .modal-nav-btn.dashboard:hover { background-color: #e0a800; transform: translateY(-1px); } .modal.fullscreen .modal-nav-btn.home { background-color: #17a2b8; color: white; } .modal.fullscreen .modal-nav-btn.home:hover { background-color: #138496; transform: translateY(-1px); } .modal.fullscreen .modal-nav-btn.logout { background-color: #dc3545; color: white; } .modal.fullscreen .modal-nav-btn.logout:hover { background-color: #c82333; transform: translateY(-1px); } /* --- Other Styles --- */ .button-container { margin-bottom: 30px; text-align: center; /* Center buttons */ } .btn { padding: 12px 25px; /* Larger buttons */ background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 1em; /* Adjust font size */ margin: 5px; /* Use margin for spacing */ transition: background-color 0.3s ease, box-shadow 0.2s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .btn:hover { background-color: #45a049; box-shadow: 0 4px 8px rgba(0,0,0,0.15); } .btn.delete { /* Consistent naming */ background-color: #f44336; } .btn.delete:hover { background-color: #da190b; } .btn.edit { /* Style for edit buttons */ background-color: #ffc107; color: #333; padding: 5px 10px; /* Smaller edit buttons */ font-size: 0.8em; margin-left: 10px; vertical-align: middle; } .btn.edit:hover { background-color: #e0a800; } label { display: block; margin-bottom: 8px; /* More space */ font-weight: bold; color: #555; } input[type="text"], textarea, select { width: 100%; /* Use 100% width */ padding: 12px; /* More padding */ margin-bottom: 18px; /* More space */ border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; font-size: 1em; } textarea { resize: vertical; min-height: 100px; /* Minimum height */ } select { margin-bottom: 25px; } .question-container { border: 1px solid #e0e0e0; padding: 20px; margin-bottom: 20px; border-radius: 5px; background-color: #f9f9f9; } .question-container h4 { margin-top: 0; margin-bottom: 15px; color: #666; font-size: 0.9em; text-transform: uppercase; } .question-container input[type="text"] { margin-bottom: 12px; } .multiple-choice-container { margin-top: 15px; padding-left: 15px; border-left: 3px solid #4CAF50; } .multiple-choice-container label { font-weight: normal; margin-bottom: 8px; } .multiple-choice-container input[type="text"] { width: calc(100% - 15px); /* Adjust width */ margin-left: 0; /* Remove indent */ } /* Display Area Styling */ #createdLessons, #createdQuizzes { margin-top: 15px; } #createdLessons div, #createdQuizzes div { background-color: #fff; /* White background */ padding: 15px; margin-bottom: 15px; border-radius: 5px; border: 1px solid #e0e0e0; display: flex; /* Use flexbox for layout */ justify-content: space-between; /* Space out content and button */ align-items: center; /* Vertically align items */ } #createdLessons div > div, #createdQuizzes div > div { flex-grow: 1; /* Allow text content to take available space */ margin-right: 15px; /* Add space between text and button (if any) */ } #createdLessons p, #createdQuizzes p { margin: 0 0 5px 0; /* Adjust margins */ } #createdLessons p strong, #createdQuizzes p strong { font-size: 1.1em; color: #333; } /* Manage Scores Modal Specific Styles */ .manage-scores-container { padding: 10px; } .scores-display-area { margin-top: 20px; border: 1px solid #ccc; padding: 15px; min-height: 100px; max-height: 400px; /* Limit height and allow scroll */ overflow-y: auto; background-color: #f9f9f9; } .scores-display-area table { width: 100%; border-collapse: collapse; margin-top: 10px; /* Add space above table */ } .scores-display-area th, .scores-display-area td { border: 1px solid #ddd; padding: 10px 12px; /* Adjust padding */ text-align: left; font-size: 0.95em; /* Slightly smaller font */ } .scores-display-area th { background-color: #e9e9e9; font-weight: bold; position: sticky; /* Make header sticky */ top: 0; /* Stick to the top of the scrollable area */ z-index: 1; /* Ensure header stays above table content */ } .scores-display-area h4 { /* Style for the quiz title */ margin-bottom: 15px; font-size: 1.2em; color: #333; } .scores-display-area .no-scores-message { font-style: italic; color: #666; text-align: center; padding: 20px; } /* --- Analytics Button (Bottom Right, Red) --- */ .analytics-btn { position: fixed; /* Fixed position */ bottom: 20px; /* Distance from bottom */ right: 20px; /* Distance from right */ padding: 12px 25px; background-color: #dc3545; /* Red color */ color: white; border: none; border-radius: 25px; /* Pill shape */ cursor: pointer; font-size: 15px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); z-index: 999; /* Ensure it's above most content but below modals */ transition: background-color 0.3s ease, transform 0.2s ease; } .analytics-btn:hover { background-color: #c82333; /* Darker red on hover */ transform: translateY(-2px); /* Slight lift on hover */ } teacher.js document.addEventListener('DOMContentLoaded', () => { // --- Login Check --- const loggedInUsername = sessionStorage.getItem('loggedInUsername'); const loggedInRole = sessionStorage.getItem('loggedInRole'); if (!loggedInUsername || !loggedInRole || loggedInRole !== 'teacher') { alert('Access denied. Please log in as a teacher.'); window.location.href = 'login.html'; // Redirect to login if not a teacher return; } // --- End Login Check --- // --- DOM Elements --- const lessonModal = document.getElementById('lessonModal'); const quizModal = document.getElementById('quizModal'); const deleteModal = document.getElementById('deleteModal'); const manageScoresModal = document.getElementById('manageScoresModal'); const analyticsModal = document.getElementById('analyticsModal'); const createLessonBtn = document.getElementById('createLessonBtn'); const createQuizBtn = document.getElementById('createQuizBtn'); const deleteLessonBtn = document.getElementById('deleteLessonBtn'); const deleteQuizBtn = document.getElementById('deleteQuizBtn'); const manageScoresBtn = document.getElementById('manageScoresBtn'); const analyticsBtn = document.getElementById('analyticsBtn'); const closeButtons = document.querySelectorAll('.close'); // Lesson Form Elements const lessonForm = document.getElementById('lessonForm'); const lessonModalTitle = document.getElementById('lessonModalTitle'); const editLessonIndexInput = document.getElementById('editLessonIndex'); const lessonTitleInput = document.getElementById('lessonTitle'); const lessonContentInput = document.getElementById('lessonContent'); const lessonSubmitBtn = document.getElementById('lessonSubmitBtn'); // Quiz Form Elements const quizForm = document.getElementById('quizForm'); const quizModalTitle = document.getElementById('quizModalTitle'); const editQuizIndexInput = document.getElementById('editQuizIndex'); const quizTypeSelect = document.getElementById('quizType'); const quizTitleInput = document.getElementById('quizTitle'); const questionsContainer = document.getElementById('questionsContainer'); const addQuestionBtn = document.getElementById('addQuestionBtn'); const quizSubmitBtn = document.getElementById('quizSubmitBtn'); // Delete Modal Elements const deleteTypeSelect = document.getElementById('deleteType'); const deleteChoiceSelect = document.getElementById('deleteChoice'); const deleteBtn = document.getElementById('deleteBtn'); // Manage Scores Modal Elements const quizSelectForScores = document.getElementById('quizSelectForScores'); const studentScoresDisplay = document.getElementById('studentScoresDisplay'); // Analytics Modal Elements const lessonCountSpan = document.getElementById('lessonCount'); const quizCountSpan = document.getElementById('quizCount'); const averageQuizScoreSpan = document.getElementById('averageQuizScore'); const modalDashboardBtn = document.getElementById('modalDashboardBtn'); const modalHomeBtn = document.getElementById('modalHomeBtn'); const modalLogoutBtn = document.getElementById('modalLogoutBtn'); // Display Areas const createdLessonsDiv = document.getElementById('createdLessons'); const createdQuizzesDiv = document.getElementById('createdQuizzes'); let questionCount = 0; const storageKeys = { lessons: 'createdLessons', quizzes: 'createdQuizzes', studentResultPrefix: 'studentQuizResults_', // Prefix for student results keys registeredUsers: 'registeredUsers' // Key for all registered users }; // --- Utility Functions --- const openModal = (modal) => { modal.style.display = "block"; if (modal.classList.contains('fullscreen')) { document.body.classList.add('modal-open'); } }; const closeModal = (modal) => { modal.style.display = "none"; if (modal.classList.contains('fullscreen')) { document.body.classList.remove('modal-open'); } // Reset forms/content on modal close if (modal.id === 'lessonModal') resetLessonForm(); if (modal.id === 'quizModal') resetQuizForm(); if (modal.id === 'manageScoresModal') { studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>'; quizSelectForScores.value = ""; } if (modal.id === 'deleteModal') { deleteTypeSelect.value = 'lesson'; deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>'; } }; // Gets array data (lessons, quizzes) const getData = (key) => { const data = localStorage.getItem(key); if (data && data.startsWith('[')) { try { return JSON.parse(data); } catch (e) { console.error("Error parsing JSON array from localStorage for key:", key, e); return []; } } return []; }; // Gets object data (registered users, student results) const getObjectData = (key) => { const data = localStorage.getItem(key); if (data && data.startsWith('{')) { try { return JSON.parse(data); } catch (e) { console.error("Error parsing JSON object from localStorage for key:", key, e); return {}; } } return {}; }; const setData = (key, data) => { try { localStorage.setItem(key, JSON.stringify(data)); } catch (e) { console.error("Error setting data to localStorage for key:", key, e); } }; // --- Lesson Functions --- const resetLessonForm = () => { lessonForm.reset(); editLessonIndexInput.value = "-1"; lessonModalTitle.textContent = "Create Lesson"; lessonSubmitBtn.textContent = "Create Lesson"; }; const updateCreatedLessons = () => { const lessons = getData(storageKeys.lessons); createdLessonsDiv.innerHTML = ''; lessons.forEach((lesson, index) => { const lessonDiv = document.createElement('div'); const contentDiv = document.createElement('div'); contentDiv.innerHTML = `<p><strong>${lesson.title}</strong></p><p>${lesson.content.substring(0, 100)}${lesson.content.length > 100 ? '...' : ''}</p>`; lessonDiv.appendChild(contentDiv); const editBtn = document.createElement('button'); editBtn.textContent = 'Edit'; editBtn.classList.add('btn', 'edit'); editBtn.dataset.index = index; editBtn.addEventListener('click', () => editLesson(index)); lessonDiv.appendChild(editBtn); createdLessonsDiv.appendChild(lessonDiv); }); updateDeleteChoices(); // Update delete dropdown after lessons update }; const editLesson = (index) => { const lessons = getData(storageKeys.lessons); if (index >= 0 && index < lessons.length) { const lesson = lessons[index]; resetLessonForm(); editLessonIndexInput.value = index; lessonTitleInput.value = lesson.title; lessonContentInput.value = lesson.content; lessonModalTitle.textContent = "Edit Lesson"; lessonSubmitBtn.textContent = "Save Changes"; openModal(lessonModal); } }; const handleLessonFormSubmit = (event) => { event.preventDefault(); const lessonData = { title: lessonTitleInput.value, content: lessonContentInput.value, }; const editIndex = parseInt(editLessonIndexInput.value, 10); let lessons = getData(storageKeys.lessons); if (editIndex > -1 && editIndex < lessons.length) { lessons[editIndex] = lessonData; alert('Lesson Updated!'); } else { lessons.push(lessonData); alert('Lesson Created!'); } setData(storageKeys.lessons, lessons); closeModal(lessonModal); updateCreatedLessons(); }; // --- Quiz Functions --- const resetQuizForm = () => { quizForm.reset(); editQuizIndexInput.value = "-1"; questionsContainer.innerHTML = ''; questionCount = 0; quizModalTitle.textContent = "Create Quiz"; quizSubmitBtn.textContent = "Create Quiz"; quizTypeSelect.disabled = false; // Re-enable type select toggleMultipleChoiceFields(); // Ensure fields match default type }; const toggleMultipleChoiceFields = () => { const selectedType = quizTypeSelect.value; const allQuestionContainers = questionsContainer.querySelectorAll('.question-container'); allQuestionContainers.forEach(qContainer => { const mcContainer = qContainer.querySelector('.multiple-choice-container'); const choiceInputs = mcContainer ? mcContainer.querySelectorAll('input[type="text"]') : []; const answerInput = qContainer.querySelector('input[name$="-correct-answer"]'); const answerLabel = answerInput ? answerInput.previousElementSibling : null; if (mcContainer) { mcContainer.style.display = selectedType === 'multiple-choice' ? 'block' : 'none'; // Set required only if multiple choice is selected choiceInputs.forEach(input => input.required = (selectedType === 'multiple-choice')); } if (answerLabel && answerLabel.tagName === 'LABEL') { answerLabel.textContent = selectedType === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):'; } }); }; const addQuestion = (questionData = null) => { const currentQIndex = questionData ? questionData.qIndex : ++questionCount; const questionDiv = document.createElement('div'); questionDiv.classList.add('question-container'); questionDiv.dataset.qIndex = currentQIndex; const qText = questionData ? questionData.questionText : ''; const qAnswer = questionData ? questionData.correctAnswer : ''; const qChoices = questionData ? questionData.choices : ['', '', '', '']; // Default empty choices questionDiv.innerHTML = ` <h4>Question ${currentQIndex}</h4> <label for="question-${currentQIndex}">Question Text:</label> <input type="text" id="question-${currentQIndex}" name="question-${currentQIndex}" value="${qText}" required><br> <div class="multiple-choice-container" style="display: ${quizTypeSelect.value === 'multiple-choice' ? 'block' : 'none'};"> <label>Choices:</label><br> <input type="text" name="question-${currentQIndex}-choice-1" placeholder="Choice 1" value="${qChoices[0] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br> <input type="text" name="question-${currentQIndex}-choice-2" placeholder="Choice 2" value="${qChoices[1] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br> <input type="text" name="question-${currentQIndex}-choice-3" placeholder="Choice 3" value="${qChoices[2] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br> <input type="text" name="question-${currentQIndex}-choice-4" placeholder="Choice 4" value="${qChoices[3] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br> </div> <label for="question-${currentQIndex}-correct-answer">${quizTypeSelect.value === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):'}</label> <input type="text" name="question-${currentQIndex}-correct-answer" value="${qAnswer}" required><br> `; questionsContainer.appendChild(questionDiv); if (!questionData) questionCount = currentQIndex; // Update global count only for new questions // No need to call toggleMultipleChoiceFields here as it's called on type change and form reset }; const updateCreatedQuizzes = () => { const quizzes = getData(storageKeys.quizzes); createdQuizzesDiv.innerHTML = ''; quizzes.forEach((quiz, index) => { const quizDiv = document.createElement('div'); const contentDiv = document.createElement('div'); // Basic validation before displaying const title = quiz.quizTitle || 'Untitled Quiz'; const type = quiz.quizType || 'N/A'; const numQuestions = Array.isArray(quiz.questions) ? quiz.questions.length : 0; contentDiv.innerHTML = `<p><strong>${title}</strong></p><p>(Type: ${type}, Questions: ${numQuestions})</p>`; quizDiv.appendChild(contentDiv); // No Edit button for quizzes currently createdQuizzesDiv.appendChild(quizDiv); }); updateDeleteChoices(); // Update delete dropdown after quizzes update populateQuizSelectForScores(); // Update scores dropdown after quizzes update }; // Edit Quiz function remains but is not called from UI const editQuiz = (index) => { const quizzes = getData(storageKeys.quizzes); if (index >= 0 && index < quizzes.length) { const quiz = quizzes[index]; resetQuizForm(); editQuizIndexInput.value = index; quizTitleInput.value = quiz.quizTitle; quizTypeSelect.value = quiz.quizType; quizTypeSelect.disabled = true; // Disable type change when editing questionCount = 0; // Reset count for adding existing questions quiz.questions.forEach((q, qIndex) => { addQuestion({ ...q, qIndex: qIndex + 1 }); // Pass existing data }); quizModalTitle.textContent = "Edit Quiz"; quizSubmitBtn.textContent = "Save Changes"; openModal(quizModal); toggleMultipleChoiceFields(); // Ensure fields match loaded quiz type } }; const handleQuizFormSubmit = (event) => { event.preventDefault(); const editIndex = parseInt(editQuizIndexInput.value, 10); const quizType = quizTypeSelect.value; const quizTitle = quizTitleInput.value; const questions = []; const questionElements = questionsContainer.querySelectorAll('.question-container'); const currentQuestionCount = questionElements.length; // Use actual number of question divs for (let i = 0; i < currentQuestionCount; i++) { const qContainer = questionElements[i]; const qIndex = qContainer.dataset.qIndex; // Get index from data attribute const questionText = qContainer.querySelector(`[name='question-${qIndex}']`)?.value.trim(); const correctAnswer = qContainer.querySelector(`[name='question-${qIndex}-correct-answer']`)?.value.trim(); const choices = []; if (!questionText || correctAnswer === undefined || correctAnswer === null || correctAnswer === "") { alert(`Please fill out question text and correct answer for Question ${qIndex}.`); return; } if (quizType === 'multiple-choice') { const choiceInputs = qContainer.querySelectorAll(`.multiple-choice-container input[type="text"]`); let choicesComplete = true; choiceInputs.forEach(input => { const choiceValue = input.value.trim(); if (!choiceValue) choicesComplete = false; choices.push(choiceValue); }); if (!choicesComplete) { alert(`Please fill out all choices for Question ${qIndex}.`); return; } // Ensure the correct answer is one of the choices provided if (!choices.includes(correctAnswer)) { alert(`The correct answer for Question ${qIndex} ("${correctAnswer}") must exactly match one of the provided choices.`); return; } } questions.push({ questionText, choices: quizType === 'multiple-choice' ? choices : [], correctAnswer }); } if (questions.length === 0) { alert('Please add at least one question to the quiz.'); return; } const quizData = { quizType, quizTitle, questions }; let quizzes = getData(storageKeys.quizzes); if (editIndex > -1 && editIndex < quizzes.length) { quizzes[editIndex] = quizData; alert('Quiz Updated!'); } else { quizzes.push(quizData); alert('Quiz Created!'); } setData(storageKeys.quizzes, quizzes); closeModal(quizModal); updateCreatedQuizzes(); }; // --- Delete Functions (Handles both Lessons and Quizzes) --- const updateDeleteChoices = () => { const deleteType = deleteTypeSelect.value; // Read the selected type deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>'; const items = getData(deleteType === "lesson" ? storageKeys.lessons : storageKeys.quizzes); items.forEach((item, index) => { const option = document.createElement('option'); option.value = index; // Use 'title' for lessons and 'quizTitle' for quizzes, provide fallback option.textContent = item.title || item.quizTitle || `${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} ${index + 1}`; deleteChoiceSelect.appendChild(option); }); deleteBtn.disabled = items.length === 0; // Disable button if no items }; const handleDelete = () => { const selectedIndex = deleteChoiceSelect.value; const deleteType = deleteTypeSelect.value; // Get the type from the dropdown if (selectedIndex === "") { alert('Please select an item to delete.'); return; } const storageKey = deleteType === 'lesson' ? storageKeys.lessons : storageKeys.quizzes; let items = getData(storageKey); const itemToDelete = items[selectedIndex]; const itemName = itemToDelete?.title || itemToDelete?.quizTitle || `${deleteType} ${parseInt(selectedIndex)+1}`; if (confirm(`Are you sure you want to delete ${deleteType} "${itemName}"? This cannot be undone.`)) { items.splice(selectedIndex, 1); setData(storageKey, items); alert(`${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} Deleted!`); // Update the correct display area if (deleteType === 'lesson') { updateCreatedLessons(); } else { updateCreatedQuizzes(); // This also updates score/delete dropdowns } closeModal(deleteModal); // Close and reset the modal } }; // --- Manage Scores Functions --- const populateQuizSelectForScores = () => { const quizzes = getData(storageKeys.quizzes); quizSelectForScores.innerHTML = '<option value="">-- Select a Quiz --</option>'; quizzes.forEach((quiz, index) => { const option = document.createElement('option'); option.value = index; // Use the index as the value option.textContent = quiz.quizTitle || `Quiz ${index + 1}`; // Fallback title quizSelectForScores.appendChild(option); }); }; // =============================================================== // START: Enhanced displayStudentScores with Debugging // =============================================================== const displayStudentScores = () => { const selectedQuizIndex = quizSelectForScores.value; studentScoresDisplay.innerHTML = ''; // Clear previous content console.log(`[DEBUG] displayStudentScores called. Selected Quiz Index: '${selectedQuizIndex}'`); if (selectedQuizIndex === "") { studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>'; console.log("[DEBUG] No quiz selected. Aborting."); return; } const quizzes = getData(storageKeys.quizzes); const selectedQuiz = quizzes[selectedQuizIndex]; if (!selectedQuiz) { console.error(`[DEBUG] Error: Could not find quiz data for index ${selectedQuizIndex}`); studentScoresDisplay.innerHTML = '<p class="no-scores-message">Error: Could not find selected quiz data.</p>'; return; } console.log("[DEBUG] Selected Quiz Data:", selectedQuiz); // --- Get ALL registered users --- const registeredUsers = getObjectData(storageKeys.registeredUsers); console.log("[DEBUG] Raw Registered Users Data from localStorage:", registeredUsers); if (Object.keys(registeredUsers).length === 0) { console.warn("[DEBUG] No registered users found in localStorage key:", storageKeys.registeredUsers); studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered users found.</p>'; return; } // --- Filter for users with role 'student' --- const studentUsernames = Object.keys(registeredUsers).filter(username => { const user = registeredUsers[username]; // Check if user exists and has a role property equal to 'student' const isStudent = user && user.role === 'student'; if (!isStudent) { console.log(`[DEBUG] Filtering out user '${username}'. Role is not 'student' or user data is malformed. User data:`, user); } return isStudent; }); console.log("[DEBUG] Filtered Student Usernames:", studentUsernames); if (studentUsernames.length === 0) { console.warn("[DEBUG] No users with role 'student' found after filtering."); studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered students found.</p>'; return; } let tableHTML = ` <h4>Scores for: ${selectedQuiz.quizTitle || 'Untitled Quiz'}</h4> <table> <thead> <tr> <th>Student</th> <th>Score</th> <th>Percentage</th> <th>Date Taken</th> </tr> </thead> <tbody> `; let scoresFound = false; // --- Iterate through each student username --- studentUsernames.forEach(username => { const studentResultKey = `${storageKeys.studentResultPrefix}${username}`; console.log(`[DEBUG] Checking results for student: '${username}' using key: '${studentResultKey}'`); // Get the results object for THIS specific student const studentResults = getObjectData(studentResultKey); console.log(`[DEBUG] Results object fetched for '${username}':`, studentResults); if (Object.keys(studentResults).length === 0) { console.log(`[DEBUG] No results object found for student '${username}' at key '${studentResultKey}'. Skipping.`); return; // Skip to the next student if no results object exists } // Check if THIS student has a result for the SPECIFICALLY selected quiz index const result = studentResults[selectedQuizIndex]; // Use bracket notation console.log(`[DEBUG] Result for quiz index '${selectedQuizIndex}' for student '${username}':`, result); // Validate the result structure before using it if (result && typeof result.score === 'number' && typeof result.total === 'number') { scoresFound = true; const score = result.score; const total = result.total; let percentage = 'N/A'; if (total > 0) { percentage = ((score / total) * 100).toFixed(1) + '%'; } else if (total === 0) { percentage = 'N/A (0 questions)'; } const dateTaken = result.timestamp ? new Date(result.timestamp).toLocaleString() : 'N/A'; console.log(`[DEBUG] Adding row for '${username}': Score=${score}, Total=${total}, Percentage=${percentage}, Date=${dateTaken}`); tableHTML += ` <tr> <td>${username}</td> <td>${score} / ${total}</td> <td>${percentage}</td> <td>${dateTaken}</td> </tr> `; } else { console.log(`[DEBUG] No valid result found for quiz index '${selectedQuizIndex}' for student '${username}' or result format is incorrect.`); } }); // End of studentUsernames.forEach if (!scoresFound) { console.warn("[DEBUG] No scores found for any student for this specific quiz index:", selectedQuizIndex); tableHTML += '<tr><td colspan="4" class="no-scores-message">No students have taken this quiz yet or results are missing.</td></tr>'; } tableHTML += '</tbody></table>'; studentScoresDisplay.innerHTML = tableHTML; console.log("[DEBUG] displayStudentScores finished."); }; // --- Analytics Modal Functions --- const openAnalyticsModal = () => { populateTeacherAnalytics(); openModal(analyticsModal); }; const closeAnalyticsModal = () => { closeModal(analyticsModal); }; const populateTeacherAnalytics = () => { const lessons = getData(storageKeys.lessons); const quizzes = getData(storageKeys.quizzes); lessonCountSpan.textContent = lessons.length; quizCountSpan.textContent = quizzes.length; let totalPercentageSum = 0; let totalQuizzesTakenCount = 0; const registeredUsers = getObjectData(storageKeys.registeredUsers); const studentUsernames = Object.keys(registeredUsers).filter(username => registeredUsers[username]?.role === 'student'); studentUsernames.forEach(username => { const studentResultKey = `${storageKeys.studentResultPrefix}${username}`; const studentResults = getObjectData(studentResultKey); // Iterate through results for this student Object.values(studentResults).forEach(result => { if (result && typeof result.score === 'number' && typeof result.total === 'number' && result.total > 0) { totalPercentageSum += (result.score / result.total) * 100; totalQuizzesTakenCount++; } }); }); if (totalQuizzesTakenCount > 0) { averageQuizScoreSpan.textContent = (totalPercentageSum / totalQuizzesTakenCount).toFixed(1) + '%'; } else { averageQuizScoreSpan.textContent = 'N/A'; } }; // --- Navigation Logic --- function goToHomepage() { window.location.href = 'homepage.html'; // Assuming homepage.html exists } function logout() { sessionStorage.removeItem('loggedInUsername'); sessionStorage.removeItem('loggedInRole'); alert('You have been logged out.'); window.location.href = 'login.html'; // Redirect to login page } // --- Event Listeners --- // Standard Modals Open/Close createLessonBtn.addEventListener('click', () => { resetLessonForm(); openModal(lessonModal); }); createQuizBtn.addEventListener('click', () => { resetQuizForm(); addQuestion(); openModal(quizModal); }); // Add one question by default deleteLessonBtn.addEventListener('click', () => { deleteTypeSelect.value = "lesson"; // Set type updateDeleteChoices(); // Populate choices for lessons openModal(deleteModal); }); deleteQuizBtn.addEventListener('click', () => { deleteTypeSelect.value = "quiz"; // Set type updateDeleteChoices(); // Populate choices for quizzes openModal(deleteModal); }); manageScoresBtn.addEventListener('click', () => { populateQuizSelectForScores(); // Ensure dropdown is up-to-date studentScoresDisplay.innerHTML='<p class="no-scores-message">Select a quiz to view student scores.</p>'; // Reset display openModal(manageScoresModal); }); closeButtons.forEach(button => { button.addEventListener('click', () => { const modalId = button.getAttribute('data-modal-id'); if (modalId) { const modalToClose = document.getElementById(modalId); if (modalToClose) closeModal(modalToClose); } }); }); // Close modal if clicking outside the content (but not on fullscreen modals) window.addEventListener('click', (event) => { if (event.target.classList.contains('modal') && !event.target.classList.contains('fullscreen')) { closeModal(event.target); } }); // Form Submissions lessonForm.addEventListener('submit', handleLessonFormSubmit); quizForm.addEventListener('submit', handleQuizFormSubmit); // Quiz Form - Add Question & Type Change addQuestionBtn.addEventListener('click', () => addQuestion()); quizTypeSelect.addEventListener('change', toggleMultipleChoiceFields); // Delete Modal - Type Change & Delete Button deleteTypeSelect.addEventListener('change', updateDeleteChoices); // Update choices when type changes deleteBtn.addEventListener('click', handleDelete); // Manage Scores Modal - Quiz Selection Change quizSelectForScores.addEventListener('change', displayStudentScores); // Analytics Modal Open/Close/Navigation analyticsBtn.addEventListener('click', openAnalyticsModal); modalDashboardBtn.addEventListener('click', closeAnalyticsModal); modalHomeBtn.addEventListener('click', goToHomepage); modalLogoutBtn.addEventListener('click', logout); // --- Initial Load --- updateCreatedLessons(); updateCreatedQuizzes(); // Load existing quizzes on page load }); student.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Student Dashboard</title> <link rel="stylesheet" href="student.css"> </head> <body> <!-- Navbar Removed --> <div class="container"> <h1>Student Dashboard</h1> <!-- Quiz Completion Status Message --> <div id="quiz-completion-status" class="completion-notice hidden"> <p>Please complete all available quizzes to view your performance analytics.</p> </div> <!-- Display Created Lessons --> <section id="lessons-section"> <h2>Available Lessons</h2> <!-- Container for lessons where event listener will be attached --> <div id="createdLessons"> <p>Loading lessons...</p> </div> </section> <!-- Display Created Quizzes --> <section id="quizzes-section"> <h2>Available Quizzes</h2> <!-- Container for quizzes where event listener will be attached --> <div id="createdQuizzes"> <p>Loading quizzes...</p> </div> </section> </div> <!-- Performance Analytics Button --> <button id="analyticsBtn" class="analytics-btn" disabled>View Performance & Analytics</button> <!-- Performance Analytics Modal --> <div id="analyticsModal" class="modal"> <div class="modal-content"> <!-- Close Button Removed --> <h2>Performance & Analytics</h2> <div class="analytics-section"> <h3>Activity</h3> <p><strong>Last Accessed:</strong> <span id="lastAccessed">N/A</span></p> </div> <div class="analytics-section"> <h3>Lesson Progress</h3> <ul id="lessonProgressList"> <li>Loading lesson status...</li> </ul> </div> <div class="analytics-section"> <h3>Quiz Scores</h3> <ul id="quizScoresList"> <li>No quizzes taken yet.</li> </ul> </div> <div class="analytics-section"> <h3>Overall Grade</h3> <p><strong id="overallGrade">N/A</strong></p> </div> <!-- Navigation Buttons Inside Modal --> <div class="modal-navigation"> <button id="modalDashboardBtn" class="modal-nav-btn dashboard">Back to Dashboard</button> <button id="modalHomeBtn" class="modal-nav-btn home">Homepage</button> <button id="modalLogoutBtn" class="modal-nav-btn logout">Logout</button> </div> </div> </div> <script src="login.js"></script> <!-- Include for getUsers/saveUsers --> <script src="student.js"></script> </body> </html> student.css /* Navbar Styles Removed */ /* Existing styles below... */ body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 20px 20px 80px 20px; /* Re-added top padding, kept side/bottom */ line-height: 1.6; } /* Prevent body scroll when modal is open */ body.modal-open { overflow: hidden; } .container { max-width: 900px; margin: 20px auto; background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } h1, h2, h3, h4 { color: #333; } h1 { text-align: center; color: #4CAF50; margin-bottom: 30px; } h2 { border-bottom: 2px solid #4CAF50; padding-bottom: 5px; margin-top: 30px; } section { margin-bottom: 30px; } /* Quiz Completion Notice */ .completion-notice { background-color: #fff3cd; color: #856404; border: 1px solid #ffeeba; padding: 15px; margin-bottom: 20px; border-radius: 5px; text-align: center; } .completion-notice p { margin: 0; font-weight: bold; } .lesson, .quiz { border: 1px solid #ddd; background-color: #f9f9f9; padding: 15px; margin-bottom: 15px; border-radius: 5px; position: relative; /* Needed for absolute positioning of button if desired */ } .lesson h4, .quiz h4 { margin-top: 0; color: #555; } /* Lesson Read Button */ .mark-read-btn { padding: 6px 12px; background-color: #17a2b8; /* Teal */ color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; margin-top: 10px; transition: background-color 0.3s ease, opacity 0.3s ease; display: inline-block; /* Or block if needed */ } .mark-read-btn:hover:not(:disabled) { background-color: #138496; } .mark-read-btn:disabled { background-color: #a6d8de; /* Lighter teal */ cursor: not-allowed; opacity: 0.7; } .btn { padding: 10px 20px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; margin-top: 10px; transition: background-color 0.3s ease; } .btn:hover:not(:disabled) { /* Ensure hover only applies when not disabled */ background-color: #45a049; } .btn:disabled { background-color: #ccc; cursor: not-allowed; opacity: 0.6; /* Slightly adjust opacity */ } .submit-quiz-btn { background-color: #007bff; } .submit-quiz-btn:hover:not(:disabled) { background-color: #0056b3; } .quiz-question { margin-top: 20px; padding-top: 15px; border-top: 1px solid #eee; } .quiz-question p strong { display: inline-block; /* Allow span to sit next to it */ margin-bottom: 10px; } /* Answer Input Styling */ .quiz-question input[type="text"] { width: calc(100% - 22px); padding: 10px; margin-top: 5px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } .quiz-question .choices label { display: block; margin-bottom: 8px; cursor: pointer; padding: 8px; border-radius: 4px; background-color: #e9e9e9; transition: background-color 0.2s ease; } .quiz-question .choices label:hover { background-color: #dcdcdc; } .quiz-question .choices input[type="radio"] { margin-right: 10px; vertical-align: middle; } /* Score Display */ .quiz-score-area { margin-top: 20px; padding: 15px; background-color: #e3f2fd; border: 1px solid #bbdefb; border-radius: 5px; text-align: center; } .quiz-score-area h3 { margin: 0; color: #0d47a1; } /* Hide elements */ .hidden { display: none; } /* --- Feedback Styles --- */ .feedback-mark { /* Container for the mark */ display: inline-block; /* Allows margin */ margin-left: 8px; font-size: 1.2em; font-weight: bold; vertical-align: middle; /* Align with text */ } .correct-mark { color: green; } .incorrect-mark { color: red; } .correct-answer-highlight { background-color: #c8e6c9 !important; border: 1px solid #a5d6a7; font-weight: bold; } .correct-answer-text { display: block; margin-top: 5px; color: #2e7d32; font-style: italic; font-size: 0.9em; } .incorrect-answer-input { border-color: #e57373 !important; background-color: #ffebee; } .incorrect-choice-selected { background-color: #ffcdd2 !important; border: 1px solid #ef9a9a; text-decoration: line-through; } .quiz-question .choices label.correct-answer-highlight, .quiz-question .choices label.incorrect-choice-selected { opacity: 1; color: #333; } /* --- Analytics Button Style --- */ .analytics-btn { position: fixed; bottom: 20px; right: 20px; padding: 12px 25px; background-color: #6f42c1; /* Purple color */ color: white; border: none; border-radius: 25px; /* Pill shape */ cursor: pointer; font-size: 15px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); z-index: 1000; /* Ensure it's above other content */ transition: background-color 0.3s ease, transform 0.2s ease, opacity 0.3s ease; } .analytics-btn:hover:not(:disabled) { background-color: #5a379b; transform: translateY(-2px); /* Slight lift on hover */ } .analytics-btn:disabled { background-color: #b3a1d1; /* Lighter purple when disabled */ cursor: not-allowed; opacity: 0.7; transform: none; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } /* --- Fullscreen Modal Styles --- */ .modal { display: none; /* Hidden by default */ position: fixed; z-index: 1001; /* Above the button */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: hidden; /* Prevent body scroll when modal is open */ background-color: #fefefe; /* Use solid background instead of overlay */ } .modal-content { background-color: transparent; /* Make content background transparent */ margin: 0; /* Remove margin */ padding: 30px; /* Adjust padding for fullscreen */ border: none; /* Remove border */ width: 100%; /* Full width */ height: 100%; /* Full height */ max-width: none; /* Remove max-width */ border-radius: 0; /* Remove border-radius */ box-shadow: none; /* Remove box-shadow */ position: relative; overflow-y: auto; /* Allow content scrolling */ box-sizing: border-box; /* Include padding in height/width */ } /* Close Button Styles Removed */ /* .close-btn { ... } */ .modal h2 { text-align: center; color: #6f42c1; margin-top: 10px; /* Add some top margin */ margin-bottom: 30px; /* Increase bottom margin */ font-size: 1.8em; /* Larger title */ } .analytics-section { margin-bottom: 25px; /* Increase spacing */ padding-bottom: 20px; border-bottom: 1px solid #eee; max-width: 800px; /* Limit width of content sections */ margin-left: auto; /* Center content sections */ margin-right: auto; } .analytics-section:last-of-type { /* Remove border from last section before nav */ border-bottom: none; } .analytics-section h3 { color: #444; margin-bottom: 15px; font-size: 1.3em; /* Larger section titles */ } #quizScoresList, #lessonProgressList { /* Apply to both lists */ list-style: none; padding: 0; max-height: 30vh; /* Adjust max height relative to viewport */ overflow-y: auto; } #quizScoresList li, #lessonProgressList li { /* Apply to both lists */ background-color: #f9f9f9; padding: 10px 15px; /* Increase padding */ margin-bottom: 8px; /* Increase spacing */ border-radius: 4px; border: 1px solid #eee; font-size: 1em; /* Slightly larger font */ display: flex; /* Use flex for alignment */ justify-content: space-between; /* Space out title and status/score */ align-items: center; } #quizScoresList li strong, #lessonProgressList li strong { /* Apply to both lists */ color: #333; margin-right: 10px; /* Add space between title and value */ } /* Lesson Progress Specific Styles in Modal */ #lessonProgressList .status-completed, #lessonProgressList .status-read { color: green; font-weight: bold; } #lessonProgressList .status-not-started { color: grey; } #overallGrade { font-size: 1.4em; /* Larger grade font */ font-weight: bold; color: #28a745; } /* Styles for Navigation Buttons inside Modal */ .modal-navigation { margin-top: 30px; /* Increase space */ padding-top: 25px; border-top: 1px solid #ccc; /* Slightly darker border */ text-align: center; display: flex; justify-content: center; gap: 20px; /* Increase gap */ max-width: 800px; /* Limit width */ margin-left: auto; margin-right: auto; } .modal-nav-btn { padding: 12px 25px; /* Larger buttons */ border: none; border-radius: 5px; cursor: pointer; font-size: 1em; /* Larger font */ font-weight: bold; transition: background-color 0.3s ease, transform 0.2s ease; } .modal-nav-btn.dashboard { /* Style for the new dashboard button */ background-color: #ffc107; /* Yellow/Orange color */ color: #333; } .modal-nav-btn.dashboard:hover { background-color: #e0a800; transform: translateY(-1px); } .modal-nav-btn.home { background-color: #17a2b8; color: white; } .modal-nav-btn.home:hover { background-color: #138496; transform: translateY(-1px); } .modal-nav-btn.logout { background-color: #dc3545; color: white; } .modal-nav-btn.logout:hover { background-color: #c82333; transform: translateY(-1px); } student.js if (!loggedInUsername || !loggedInRole || loggedInRole !== 'student') { alert('Access denied. Please log in as a student.'); // Ensure login.js is loaded if redirecting to index.html which might be the login page window.location.href = 'index.html'; // Redirect if not a student return; } // --- End Login Check --- // --- DOM Elements --- const createdLessonsDiv = document.getElementById('createdLessons'); const createdQuizzesDiv = document.getElementById('createdQuizzes'); const quizCompletionStatusDiv = document.getElementById('quiz-completion-status'); // Analytics Elements const analyticsBtn = document.getElementById('analyticsBtn'); const analyticsModal = document.getElementById('analyticsModal'); const lastAccessedSpan = document.getElementById('lastAccessed'); const lessonProgressListUl = document.getElementById('lessonProgressList'); // Added for modal const quizScoresListUl = document.getElementById('quizScoresList'); const overallGradeSpan = document.getElementById('overallGrade'); // Modal Navigation Elements const modalDashboardBtn = document.getElementById('modalDashboardBtn'); const modalHomeBtn = document.getElementById('modalHomeBtn'); const modalLogoutBtn = document.getElementById('modalLogoutBtn'); // --- Storage Keys --- const storageKeys = { users: 'users', // Key for the main user object containing all users lessons: 'createdLessons', // Global lessons created by teacher quizzes: 'createdQuizzes', // Global quizzes created by teacher lastAccessed: `studentLastAccessed_${loggedInUsername}` // Student-specific last access }; // --- Utility Functions (Ensure login.js is included for getUsers/saveUsers) --- // getUsers() and saveUsers() are assumed to be available from login.js if (typeof getUsers !== 'function' || typeof saveUsers !== 'function') { console.error("Error: getUsers or saveUsers function not found. Make sure login.js is included before student.js"); alert("A critical error occurred. Please try refreshing the page or logging in again."); // Optionally redirect or disable functionality return; } // --- Get Current Student Data --- // Helper to safely get the current student's data object from the main users store function getCurrentStudentData() { const users = getUsers(); const studentData = users[loggedInUsername]; if (studentData && studentData.role === 'student') { // Initialize progress arrays if they don't exist (robustness) if (!Array.isArray(studentData.quizScores)) { studentData.quizScores = []; } if (!Array.isArray(studentData.lessonProgress)) { studentData.lessonProgress = []; } return studentData; } console.error("Could not find valid student data for username:", loggedInUsername); // Maybe redirect or show error if student data is corrupted/missing alert("Error: Could not load your data. Please try logging in again."); logout(); // Log out if data is missing return null; // Return null to indicate failure } // --- Track Last Accessed --- function recordLastAccessed() { const now = new Date(); localStorage.setItem(storageKeys.lastAccessed, now.toISOString()); } // --- Lesson Display & Tracking --- function updateCreatedLessons() { const globalLessons = JSON.parse(localStorage.getItem(storageKeys.lessons) || '[]'); const studentData = getCurrentStudentData(); if (!studentData) return; // Stop if student data failed to load createdLessonsDiv.innerHTML = ''; // Clear existing lessons if (globalLessons.length === 0) { createdLessonsDiv.innerHTML = '<p>No lessons available.</p>'; return; } globalLessons.forEach((lesson, index) => { // Basic validation const title = lesson.title || 'Untitled Lesson'; const content = lesson.content || 'No content.'; const lessonId = `lesson-${index}`; // Simple ID based on index // Check student's progress for this lesson const progressEntry = studentData.lessonProgress.find(p => p.lessonName === title); const isRead = progressEntry && (progressEntry.status === 'read' || progressEntry.status === 'completed'); // Consider both 'read' and 'completed' as read const lessonDiv = document.createElement('div'); lessonDiv.classList.add('lesson'); lessonDiv.innerHTML = ` <h4>${title}</h4> <p>${content}</p> <button class="mark-read-btn" data-lesson-title="${title}" ${isRead ? 'disabled' : ''}> ${isRead ? 'Read' : 'Mark as Read'} </button> `; createdLessonsDiv.appendChild(lessonDiv); }); } // --- Event Delegation for Lesson Buttons --- createdLessonsDiv.addEventListener('click', (event) => { const target = event.target; if (target.classList.contains('mark-read-btn') && !target.disabled) { const lessonTitle = target.dataset.lessonTitle; markLessonAsRead(lessonTitle, target); } }); function markLessonAsRead(lessonTitle, buttonElement) { const users = getUsers(); const studentData = users[loggedInUsername]; // Get current data again if (!studentData) { alert("Error updating lesson status."); return; } // Ensure lessonProgress array exists if (!Array.isArray(studentData.lessonProgress)) { studentData.lessonProgress = []; } // Find the progress entry or create it let progressEntry = studentData.lessonProgress.find(p => p.lessonName === lessonTitle); if (progressEntry) { progressEntry.status = 'read'; // Update status to 'read' } else { // Add new entry if it doesn't exist studentData.lessonProgress.push({ lessonName: lessonTitle, status: 'read' }); } // Save the updated users object saveUsers(users); // Update the button state buttonElement.disabled = true; buttonElement.textContent = 'Read'; console.log(`Lesson "${lessonTitle}" marked as read for ${loggedInUsername}`); // Optionally, update the analytics modal if it's open if (analyticsModal.style.display === 'block') { populateAnalyticsData(); } } // --- Quiz Display and Taking Logic --- function updateCreatedQuizzes() { console.log("Updating created quizzes display for student:", loggedInUsername); const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]'); const studentData = getCurrentStudentData(); if (!studentData) return; // Stop if student data failed to load createdQuizzesDiv.innerHTML = ''; // Clear previous content if (globalQuizzes.length === 0) { createdQuizzesDiv.innerHTML = '<p>No quizzes available.</p>'; checkAndEnforceQuizCompletion(); // Check even if no quizzes return; } globalQuizzes.forEach((quiz, index) => { // Basic validation of quiz structure if (!quiz || typeof quiz.quizTitle === 'undefined' || !Array.isArray(quiz.questions)) { console.warn(`Skipping invalid quiz data at index ${index}:`, quiz); return; // Skip rendering this invalid quiz } const quizTitle = quiz.quizTitle || 'Untitled Quiz'; // Check if this student has taken this quiz by looking in their main data const resultData = studentData.quizScores.find(score => score.quizName === quizTitle); const hasTaken = !!resultData; // True if resultData is found console.log(`Quiz Index: ${index}, Title: ${quizTitle}, Has Taken: ${hasTaken}`); const quizDiv = document.createElement('div'); quizDiv.classList.add('quiz'); quizDiv.id = `quiz-${index}`; quizDiv.innerHTML = ` <h4>${quizTitle}</h4> <p>Type: ${quiz.quizType || 'N/A'}</p> <p>Number of questions: ${quiz.questions.length}</p> <button class="btn take-quiz-btn" data-quiz-index="${index}" ${hasTaken ? 'disabled' : ''}>${hasTaken ? 'Quiz Taken' : 'Take Quiz'}</button> <div class="quiz-questions-area" id="quiz-area-${index}" style="display: none;"></div> <div class="quiz-score-area" id="score-area-${index}" style="display: ${hasTaken ? 'block' : 'none'};"> ${hasTaken && resultData ? `<h3>Your Score: ${resultData.score}%</h3>` : ''} </div> `; createdQuizzesDiv.appendChild(quizDiv); }); checkAndEnforceQuizCompletion(); // Check completion after rendering quizzes } // --- Event Delegation for Quiz Buttons --- createdQuizzesDiv.addEventListener('click', (event) => { const target = event.target; // The element that was actually clicked // Check if the clicked element is a "take-quiz-btn" or inside one const takeButton = target.closest('.take-quiz-btn'); if (takeButton && !takeButton.disabled) { console.log("Take Quiz button clicked via delegation for index:", takeButton.dataset.quizIndex); startQuiz(takeButton); // Pass the button element itself return; // Stop further processing for this click } // Check if the clicked element is a "submit-quiz-btn" or inside one const submitButton = target.closest('.submit-quiz-btn'); if (submitButton && !submitButton.disabled) { console.log("Submit Quiz button clicked via delegation for index:", submitButton.dataset.quizIndex); submitQuiz(submitButton); // Pass the button element itself return; // Stop further processing for this click } }); function startQuiz(buttonElement) { // Accepts the button element directly const quizIndex = buttonElement.dataset.quizIndex; console.log('startQuiz called for index:', quizIndex); const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]'); // Validate quiz index and data if (quizIndex === undefined || !globalQuizzes[quizIndex] || !Array.isArray(globalQuizzes[quizIndex].questions)) { console.error(`Invalid quiz index or data for index ${quizIndex}`); alert("Error: Could not load quiz data."); return; } const quiz = globalQuizzes[quizIndex]; const questionsArea = document.getElementById(`quiz-area-${quizIndex}`); const scoreArea = document.getElementById(`score-area-${quizIndex}`); const takeQuizButton = buttonElement; // The button that was clicked if (!questionsArea || !scoreArea) { console.error(`Could not find questionsArea or scoreArea for quiz index ${quizIndex}`); alert("Error: Could not display quiz."); return; } // Hide other open quiz forms if any, and show their "Take Quiz" buttons document.querySelectorAll('.quiz-questions-area').forEach(area => { if (area.id !== `quiz-area-${quizIndex}`) { area.style.display = 'none'; const otherQuizIndex = area.id.split('-')[2]; const otherTakeButton = document.querySelector(`.take-quiz-btn[data-quiz-index="${otherQuizIndex}"]`); // Check if the other quiz has been taken using the main student data const studentData = getCurrentStudentData(); const otherQuizTitle = globalQuizzes[otherQuizIndex]?.quizTitle; const otherQuizTaken = studentData?.quizScores.some(s => s.quizName === otherQuizTitle); if (otherTakeButton && !otherQuizTaken) { // Only show if not already taken otherTakeButton.style.display = 'inline-block'; } } }); questionsArea.innerHTML = ''; // Clear previous content if any scoreArea.innerHTML = ''; // Clear score area scoreArea.style.display = 'none'; // Hide score area questionsArea.style.display = 'block'; // Show questions area takeQuizButton.style.display = 'none'; // Hide the clicked "Take Quiz" button quiz.questions.forEach((question, qIndex) => { // Basic validation of question structure if (!question || typeof question.questionText === 'undefined') { console.warn(`Skipping invalid question data at qIndex ${qIndex} for quiz ${quizIndex}:`, question); return; // Skip rendering invalid question } const questionDiv = document.createElement('div'); questionDiv.classList.add('quiz-question'); let answerHtml = ''; if (quiz.quizType === 'identification') { answerHtml = `<label for="answer-${quizIndex}-${qIndex}">Your Answer:</label><input type="text" id="answer-${quizIndex}-${qIndex}" name="answer-${quizIndex}-${qIndex}" required>`; } else if (quiz.quizType === 'multiple-choice') { answerHtml = '<div class="choices">'; const choices = Array.isArray(question.choices) ? question.choices : []; if (choices.length === 0) { console.warn(`No choices found for multiple-choice question qIndex ${qIndex} in quiz ${quizIndex}`); } // Shuffle choices before displaying (optional, but good practice) const shuffledChoices = [...choices].sort(() => Math.random() - 0.5); shuffledChoices.forEach((choice, cIndex) => { // Ensure choice text is displayed correctly, even if null/undefined const choiceText = (choice !== null && choice !== undefined) ? choice : `Choice ${cIndex + 1}`; // Use the original choice value for the radio button's value attribute const choiceValue = (choice !== null && choice !== undefined) ? choice : `__choice_${cIndex}__`; // Handle potential null/undefined values answerHtml += `<label><input type="radio" name="answer-${quizIndex}-${qIndex}" value="${choiceValue}" id="choice-${quizIndex}-${qIndex}-${cIndex}" required> ${choiceText}</label>`; }); answerHtml += '</div>'; } else { console.warn(`Unsupported quiz type "${quiz.quizType}" for question qIndex ${qIndex} in quiz ${quizIndex}`); answerHtml = '<p><em>Unsupported question type.</em></p>'; } questionDiv.innerHTML = `<p><strong>${qIndex + 1}. ${question.questionText}</strong></p>${answerHtml}`; questionsArea.appendChild(questionDiv); }); // Add submit button only if valid questions were rendered if (questionsArea.children.length > 0 && !questionsArea.querySelector('.submit-quiz-btn')) { const submitButton = document.createElement('button'); submitButton.textContent = 'Submit Quiz'; submitButton.classList.add('btn', 'submit-quiz-btn'); submitButton.dataset.quizIndex = quizIndex; // Listener is handled by delegation, no need to add here questionsArea.appendChild(submitButton); } else if (questionsArea.children.length === 0) { // Handle case where a quiz has no valid questions questionsArea.innerHTML = '<p><em>No valid questions found for this quiz. Cannot submit.</em></p>'; // Optionally re-display the "Take Quiz" button or show a message takeQuizButton.style.display = 'inline-block'; // Show button again takeQuizButton.disabled = true; // Disable it as it's problematic takeQuizButton.textContent = 'Quiz Error'; } } function submitQuiz(buttonElement) { // Accepts the button element directly const quizIndex = buttonElement.dataset.quizIndex; console.log('submitQuiz called for index:', quizIndex); const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]'); // Validate quiz index and data if (quizIndex === undefined || !globalQuizzes[quizIndex] || !Array.isArray(globalQuizzes[quizIndex].questions)) { console.error(`Invalid quiz index or data for submission: ${quizIndex}`); alert("Error: Could not submit quiz data."); return; } const quiz = globalQuizzes[quizIndex]; const questionsArea = buttonElement.closest('.quiz-questions-area'); // Find parent question area const scoreArea = document.getElementById(`score-area-${quizIndex}`); if (!questionsArea || !scoreArea) { console.error("Could not find questions or score area for quiz index:", quizIndex); alert("Error submitting quiz. Please try again."); return; } let score = 0; let allAnswered = true; // Filter out potentially invalid questions from the quiz data before counting/iterating const validQuestions = quiz.questions.filter(q => q && typeof q.questionText !== 'undefined'); const totalValidQuestions = validQuestions.length; // Clear previous feedback before evaluating questionsArea.querySelectorAll('.feedback-mark, .correct-answer-text').forEach(el => el.remove()); questionsArea.querySelectorAll('.correct-answer-highlight, .incorrect-choice-selected, .incorrect-answer-input').forEach(el => { el.classList.remove('correct-answer-highlight', 'incorrect-choice-selected', 'incorrect-answer-input'); if (el.tagName === 'LABEL') { el.style.textDecoration = 'none'; } }); // Re-enable inputs temporarily for validation, disable later questionsArea.querySelectorAll('input[type="text"], input[type="radio"]').forEach(input => input.disabled = false); // Iterate through each *valid* question defined in the quiz data validQuestions.forEach((question, qIndex) => { let studentAnswer = null; const correctAnswer = question.correctAnswer; // Find the corresponding question element in the DOM based on its position among valid questions const questionElement = questionsArea.querySelector(`.quiz-question:nth-child(${qIndex + 1})`); // Assumes DOM order matches validQuestions order const questionNumberElement = questionElement ? questionElement.querySelector('p strong') : null; if (!questionElement || !questionNumberElement) { console.warn(`Could not find question element in DOM for valid qIndex ${qIndex} during submission in quiz ${quizIndex}`); allAnswered = false; // Consider it unanswered if the element is missing return; // Skip this question } // --- Get Student Answer and Validate --- if (quiz.quizType === 'identification') { const inputElement = questionElement.querySelector(`input[type="text"]`); if (!inputElement) { console.warn(`Missing input element for identification qIndex ${qIndex}`); allAnswered = false; return; } studentAnswer = inputElement.value.trim(); if (studentAnswer === "") allAnswered = false; else if (correctAnswer !== undefined && correctAnswer !== null && studentAnswer.toLowerCase() === String(correctAnswer).toLowerCase()) score++; } else if (quiz.quizType === 'multiple-choice') { const checkedRadio = questionElement.querySelector(`input[type="radio"]:checked`); if (!checkedRadio) allAnswered = false; else { studentAnswer = checkedRadio.value; if (studentAnswer === String(correctAnswer)) score++; } } }); // End of validQuestions.forEach for validation // --- Check if all questions were answered --- if (!allAnswered) { alert('Please answer all questions before submitting.'); questionsArea.querySelectorAll('input[type="text"], input[type="radio"]').forEach(input => input.disabled = false); // Re-enable return; // Stop submission } // --- If all answered, proceed to show feedback and save --- // Disable all inputs now that submission is final questionsArea.querySelectorAll('input[type="text"], input[type="radio"]').forEach(input => input.disabled = true); // Iterate again through valid questions to apply feedback styles validQuestions.forEach((question, qIndex) => { const questionElement = questionsArea.querySelector(`.quiz-question:nth-child(${qIndex + 1})`); if (!questionElement) return; const questionNumberElement = questionElement.querySelector('p strong'); const correctAnswer = question.correctAnswer; let studentAnswer = null; let isCorrect = false; // Re-evaluate for feedback if (quiz.quizType === 'identification') { const inputElement = questionElement.querySelector(`input[type="text"]`); studentAnswer = inputElement ? inputElement.value.trim() : ''; isCorrect = (correctAnswer !== undefined && correctAnswer !== null && studentAnswer.toLowerCase() === String(correctAnswer).toLowerCase()); if (!isCorrect && inputElement) { inputElement.classList.add('incorrect-answer-input'); if (correctAnswer !== undefined && correctAnswer !== null) { const correctAnswerSpan = document.createElement('span'); correctAnswerSpan.classList.add('correct-answer-text'); correctAnswerSpan.textContent = `Correct answer: ${correctAnswer}`; inputElement.parentNode.insertBefore(correctAnswerSpan, inputElement.nextSibling); } } } else if (quiz.quizType === 'multiple-choice') { const radioButtons = questionElement.querySelectorAll(`input[type="radio"]`); const checkedRadio = questionElement.querySelector(`input[type="radio"]:checked`); studentAnswer = checkedRadio ? checkedRadio.value : null; isCorrect = (studentAnswer === String(correctAnswer)); radioButtons.forEach(radio => { const choiceLabel = radio.closest('label'); if (!choiceLabel) return; // Highlight the correct answer's label if (radio.value === String(correctAnswer)) { choiceLabel.classList.add('correct-answer-highlight'); } // If this radio was checked and it's incorrect, style it if (radio.checked && !isCorrect) { choiceLabel.classList.add('incorrect-choice-selected'); choiceLabel.style.textDecoration = 'line-through'; // Add line-through } }); } // Add checkmark or cross if (questionNumberElement) { const feedbackMark = document.createElement('span'); feedbackMark.classList.add('feedback-mark'); feedbackMark.textContent = isCorrect ? '✓' : '✗'; feedbackMark.classList.add(isCorrect ? 'correct-mark' : 'incorrect-mark'); // Ensure no duplicate marks const existingMark = questionNumberElement.querySelector('.feedback-mark'); if (existingMark) existingMark.remove(); questionNumberElement.appendChild(feedbackMark); } }); // End of feedback loop // --- Display Final Score and Save --- const percentageScore = totalValidQuestions > 0 ? Math.round((score / totalValidQuestions) * 100) : 0; scoreArea.innerHTML = `<h3>Your Score: ${percentageScore}%</h3>`; // Show percentage scoreArea.style.display = 'block'; buttonElement.disabled = true; // Disable the submit button permanently buttonElement.textContent = 'Submitted'; // Find the original "Take Quiz" button again and ensure it's disabled and text updated const originalTakeButton = document.querySelector(`.take-quiz-btn[data-quiz-index="${quizIndex}"]`); if (originalTakeButton) { originalTakeButton.disabled = true; originalTakeButton.textContent = 'Quiz Taken'; originalTakeButton.style.display = 'inline-block'; // Ensure it's visible again } // Save the result (percentage score) to the main student data saveQuizResult(quiz.quizTitle || 'Untitled Quiz', percentageScore); checkAndEnforceQuizCompletion(); // Update analytics button status } function saveQuizResult(quizTitle, percentageScore) { const users = getUsers(); const studentData = users[loggedInUsername]; if (!studentData) { console.error("Cannot save quiz result: Student data not found."); return; } // Ensure quizScores array exists if (!Array.isArray(studentData.quizScores)) { studentData.quizScores = []; } // Find if a result for this quiz already exists const existingResultIndex = studentData.quizScores.findIndex(q => q.quizName === quizTitle); const newResult = { quizName: quizTitle, score: percentageScore, // Store the percentage score timestamp: new Date().toISOString() }; if (existingResultIndex > -1) { // Update existing result studentData.quizScores[existingResultIndex] = newResult; console.log("Quiz result updated for:", quizTitle, "for student:", loggedInUsername); } else { // Add new result studentData.quizScores.push(newResult); console.log("Quiz result saved for:", quizTitle, "for student:", loggedInUsername); } // Save the entire updated users object back to localStorage saveUsers(users); } // --- Quiz Completion Enforcement --- function checkAndEnforceQuizCompletion() { const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]'); const studentData = getCurrentStudentData(); if (!studentData) return; // Can't check if data is missing let allValidQuizzesTaken = true; // Filter global quizzes to only include valid ones const validGlobalQuizzes = globalQuizzes.filter(quiz => quiz && typeof quiz.quizTitle !== 'undefined' && Array.isArray(quiz.questions)); if (validGlobalQuizzes.length === 0) { allValidQuizzesTaken = true; // No valid quizzes to take } else { for (const quiz of validGlobalQuizzes) { const quizTitle = quiz.quizTitle; // Check if THIS student has taken this VALID quiz by looking in their data const hasTaken = studentData.quizScores.some(score => score.quizName === quizTitle); if (!hasTaken) { allValidQuizzesTaken = false; break; // Found an untaken, valid quiz } } } console.log("All valid quizzes taken by", loggedInUsername, ":", allValidQuizzesTaken); if (allValidQuizzesTaken) { quizCompletionStatusDiv.classList.add('hidden'); analyticsBtn.disabled = false; // Enable button console.log("Analytics button enabled for", loggedInUsername); } else { quizCompletionStatusDiv.classList.remove('hidden'); analyticsBtn.disabled = true; // Disable button console.log("Analytics button disabled for", loggedInUsername); } } // --- Analytics Modal Logic --- function openAnalyticsModal() { checkAndEnforceQuizCompletion(); // Re-check before opening if (analyticsBtn.disabled) { alert("Please complete all available quizzes before viewing analytics."); return; } populateAnalyticsData(); analyticsModal.style.display = 'block'; document.body.classList.add('modal-open'); // Prevent body scroll } function closeAnalyticsModal() { analyticsModal.style.display = 'none'; document.body.classList.remove('modal-open'); // Allow body scroll again } function populateAnalyticsData() { const studentData = getCurrentStudentData(); if (!studentData) return; // Stop if data is missing // Get last accessed time for this student const lastAccessedISO = localStorage.getItem(storageKeys.lastAccessed); lastAccessedSpan.textContent = lastAccessedISO ? new Date(lastAccessedISO).toLocaleString() : 'Not recorded yet.'; // --- Populate Lesson Progress --- lessonProgressListUl.innerHTML = ''; // Clear previous list const globalLessons = JSON.parse(localStorage.getItem(storageKeys.lessons) || '[]'); if (globalLessons.length > 0) { // Ensure studentData.lessonProgress exists const lessonProgress = Array.isArray(studentData.lessonProgress) ? studentData.lessonProgress : []; globalLessons.forEach(lesson => { const title = lesson.title || 'Untitled Lesson'; const progressEntry = lessonProgress.find(p => p.lessonName === title); const status = progressEntry ? progressEntry.status : 'not started'; const statusClass = `status-${status.toLowerCase().replace(' ', '-')}`; const listItem = document.createElement('li'); listItem.innerHTML = `<strong>${title}:</strong> <span class="${statusClass}">${status}</span>`; lessonProgressListUl.appendChild(listItem); }); } else { lessonProgressListUl.innerHTML = '<li>No lessons available.</li>'; } // --- Populate Quiz Scores --- quizScoresListUl.innerHTML = ''; // Clear previous list const quizScores = studentData.quizScores; // Get scores directly from student data if (quizScores.length === 0) { quizScoresListUl.innerHTML = '<li>No quizzes taken yet.</li>'; overallGradeSpan.textContent = 'N/A'; return; // Exit early if no scores } let totalPercentage = 0; let numberOfQuizzesTaken = 0; // Sort scores alphabetically by quiz name for consistent display quizScores.sort((a, b) => a.quizName.localeCompare(b.quizName)); quizScores.forEach(result => { // Ensure result has expected properties before calculating if (result && typeof result.quizName !== 'undefined' && typeof result.score === 'number') { const listItem = document.createElement('li'); listItem.innerHTML = `<strong>${result.quizName}:</strong> ${result.score}%`; quizScoresListUl.appendChild(listItem); totalPercentage += result.score; numberOfQuizzesTaken++; } else { console.warn(`Invalid score data found in student results:`, result); } }); // Calculate overall grade as the average of the percentage scores of quizzes taken overallGradeSpan.textContent = numberOfQuizzesTaken > 0 ? `${(totalPercentage / numberOfQuizzesTaken).toFixed(1)}%` : 'N/A'; } // --- Navigation Logic --- function goToHomepage() { // Determine homepage based on role if necessary, or assume a general one window.location.href = 'homepage.html'; // Assuming homepage.html exists } function logout() { sessionStorage.removeItem('loggedInUsername'); sessionStorage.removeItem('loggedInRole'); // Also clear student-specific items if desired localStorage.removeItem(storageKeys.lastAccessed); alert('You have been logged out.'); window.location.href = 'index.html'; // Redirect to login page (index.html) } // --- Event Listeners --- if (analyticsBtn) analyticsBtn.addEventListener('click', openAnalyticsModal); if (modalDashboardBtn) modalDashboardBtn.addEventListener('click', closeAnalyticsModal); if (modalHomeBtn) modalHomeBtn.addEventListener('click', goToHomepage); if (modalLogoutBtn) modalLogoutBtn.addEventListener('click', logout); // --- Initial Load --- recordLastAccessed(); // Record access time on load updateCreatedLessons(); updateCreatedQuizzes(); // Initial population and completion check for this student parent.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Parent Access - Find Student</title> <link rel="stylesheet" href="parent.css"> <!-- Use new CSS --> </head> <body> <div class="access-container"> <h2>Find Student Record</h2> <p>Please enter the student's details to view their progress.</p> <input type="text" id="studentFullName" placeholder="Enter Student's Full Name"> <input type="text" id="studentIdNumber" placeholder="Enter Student's ID Number"> <button onclick="verifyStudent()">View Dashboard</button> <p id="accessErrorMessage" class="error-message"></p> <p><a href="login.html">Back to Login</a></p> </div> <script src="parent.js"></script> <!-- Use new JS --> <script src="login.js"></script> <!-- Include login.js for getUsers function --> </body> </html> parent.css /* Reusing and adapting styles from login.css */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #e2a2a2, #f4f4f4); /* Slightly different gradient for parent section */ display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; } .access-container, .dashboard-container { background: #fff; width: 100%; max-width: 600px; /* Wider for dashboard */ padding: 30px; border-radius: 12px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); text-align: left; /* Align text left for dashboard content */ } .access-container { max-width: 450px; /* Keep access container similar to login */ text-align: center; /* Center align access form */ } h2, h3 { color: #333; margin-bottom: 20px; font-weight: bold; } h2 { font-size: 24px; text-align: center; /* Center main headings */ } h3 { font-size: 20px; margin-top: 25px; /* Add space above subheadings */ border-bottom: 1px solid #eee; /* Separator line */ padding-bottom: 10px; } input, button { /* Styles for access page */ width: 100%; padding: 15px; margin: 10px 0; border-radius: 8px; border: 1px solid #ddd; font-size: 16px; outline: none; transition: all 0.3s ease; } input:focus, button:focus { border-color: #c82333; /* Parent theme color */ box-shadow: 0 0 8px rgba(200, 35, 51, 0.3); } button { background: #c82333; /* Parent theme color */ color: white; border: none; cursor: pointer; font-weight: bold; transition: background 0.3s ease; } button:hover { background: #a81d2a; } .error-message { color: red; font-size: 14px; margin-top: 10px; min-height: 1.2em; /* Reserve space */ text-align: center; } p { font-size: 14px; color: #666; margin-top: 15px; line-height: 1.6; } .access-container p { text-align: center; /* Center paragraph text in access container */ } p a { color: #c82333; /* Parent theme color */ text-decoration: none; } p a:hover { text-decoration: underline; } /* Dashboard specific styles */ .dashboard-container div { margin-bottom: 20px; } .dashboard-container ul { list-style: none; padding-left: 0; } .dashboard-container li { background-color: #f9f9f9; border: 1px solid #eee; padding: 10px 15px; margin-bottom: 8px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; } .dashboard-container li span { font-weight: bold; } .lesson-progress .status-completed { color: green; } .lesson-progress .status-read { color: orange; } .lesson-progress .status-not-started { color: grey; } .student-info p { margin-top: 5px; } parentdash.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Parent Dashboard</title> <link rel="stylesheet" href="parent.css"> <!-- Use new CSS --> </head> <body> <div class="dashboard-container"> <h2 id="dashboardTitle">Student Progress Dashboard</h2> <div class="student-info"> <h3>Student Information</h3> <p><strong>Name:</strong> <span id="studentName"></span></p> <p><strong>ID:</strong> <span id="studentId"></span></p> </div> <div class="quiz-scores"> <h3>Quiz Scores</h3> <ul id="quizList"> <!-- Scores will be loaded here by JS --> <li>Loading scores...</li> </ul> </div> <div class="lesson-progress"> <h3>Lesson Progress</h3> <ul id="lessonList"> <!-- Progress will be loaded here by JS --> <li>Loading progress...</li> </ul> </div> <p><a href="parent.html">Look up another student</a></p> <p><a href="login.html" onclick="logoutParent()">Logout</a></p> </div> <script src="parent.js"></script> <!-- Use new JS --> <script src="login.js"></script> <!-- Include login.js for getUsers function --> </body> </html> parent.js // ========== Parent Access Page (parent-access.html) ========== function verifyStudent() { const studentFullNameInput = document.getElementById("studentFullName"); const studentIdNumberInput = document.getElementById("studentIdNumber"); const errorMessage = document.getElementById("accessErrorMessage"); const studentFullName = studentFullNameInput.value.trim(); const studentIdNumber = studentIdNumberInput.value.trim(); errorMessage.textContent = ''; // Clear previous errors if (!studentFullName || !studentIdNumber) { errorMessage.textContent = "Please enter both the student's full name and ID number."; return; } const users = getUsers(); // Assumes getUsers() is available (from login.js) let foundStudentUsername = null; // Iterate through all users to find a matching student for (const username in users) { const userData = users[username]; if (userData.role === 'student' && userData.fullName.toLowerCase() === studentFullName.toLowerCase() && // Case-insensitive name check userData.studentId === studentIdNumber) { foundStudentUsername = username; break; // Stop searching once found } } if (foundStudentUsername) { // Student found, store the username (key) for the dashboard sessionStorage.setItem('viewingStudentUsername', foundStudentUsername); // Redirect to the dashboard window.location.href = "parent-dashboard.html"; } else { // No matching student found errorMessage.textContent = "No student record found matching the provided name and ID. Please check the details and try again."; studentFullNameInput.value = ''; // Clear fields on error studentIdNumberInput.value = ''; } } // ========== Parent Dashboard Page (parent-dashboard.html) ========== function populateDashboard() { const viewingStudentUsername = sessionStorage.getItem('viewingStudentUsername'); const dashboardTitle = document.getElementById('dashboardTitle'); // Security check: If no student username is in session storage, redirect back if (!viewingStudentUsername) { alert("No student selected. Redirecting to access page."); window.location.href = "parent-access.html"; return; // Stop execution } const users = getUsers(); // Assumes getUsers() is available const studentData = users[viewingStudentUsername]; if (!studentData || studentData.role !== 'student') { alert("Error retrieving student data. Redirecting."); sessionStorage.removeItem('viewingStudentUsername'); // Clear invalid session item window.location.href = "parent-access.html"; return; // Stop execution } // Populate Student Info document.getElementById('studentName').textContent = studentData.fullName || 'N/A'; document.getElementById('studentId').textContent = studentData.studentId || 'N/A'; dashboardTitle.textContent = `${studentData.fullName}'s Progress Dashboard`; // Populate Quiz Scores const quizList = document.getElementById('quizList'); quizList.innerHTML = ''; // Clear loading message if (studentData.quizScores && studentData.quizScores.length > 0) { studentData.quizScores.forEach(quiz => { const listItem = document.createElement('li'); listItem.innerHTML = `${quiz.quizName} <span>${quiz.score}%</span>`; quizList.appendChild(listItem); }); } else { quizList.innerHTML = '<li>No quiz scores available.</li>'; } // Populate Lesson Progress const lessonList = document.getElementById('lessonList'); lessonList.innerHTML = ''; // Clear loading message if (studentData.lessonProgress && studentData.lessonProgress.length > 0) { studentData.lessonProgress.forEach(lesson => { const listItem = document.createElement('li'); // Add class for styling based on status const statusClass = `status-${lesson.status.toLowerCase().replace(' ', '-')}`; listItem.innerHTML = `${lesson.lessonName} <span class="${statusClass}">${lesson.status}</span>`; lessonList.appendChild(listItem); }); } else { lessonList.innerHTML = '<li>No lesson progress available.</li>'; } } function logoutParent() { // Clear specific session storage items related to parent view sessionStorage.removeItem('viewingStudentUsername'); // Optionally clear parent login info if you stored it, e.g., sessionStorage.removeItem('loggedInUsername'); // Redirect to main login page window.location.href = 'index.html'; } // Run dashboard population logic only if we are on the dashboard page // Check for an element unique to the dashboard if (document.getElementById('dashboardTitle')) { document.addEventListener('DOMContentLoaded', populateDashboard); }

Okay, I will refactor the code to create a more proper and functional Learning Management System based on your existing structure.

Here are the key changes:

  1. File Renaming: Renamed parent.html to parent-access.html and parentdash.html to parent-dashboard.html for clarity.
  2. Parent Login Flow: Parents logging in will now be redirected directly to the parent-access.html page to look up their student, bypassing the generic homepage.html.
  3. Centralized Student Data: Student quiz scores (score, total, quizTitle, timestamp) and lesson progress (lessonName, status, timestamp) are now stored directly within the student's object in the main users data in localStorage. This simplifies data management and retrieval for teachers and parents. The old studentQuizResults_username pattern is removed.
  4. Consistent User Data Handling: Ensured all JavaScript files (login.js, teacher.js, student.js, parent.js) consistently use the getUsers and saveUsers functions (assuming login.js is included where needed) to interact with the main users data in localStorage.
  5. Quiz Submission Reliability: Updated the student quiz submission logic (student.js) to use data attributes (data-qindex) for matching questions and answers, making it more robust than relying on DOM order.
  6. Data Display Updates: Updated Teacher (teacher.js) and Parent (parent.js) dashboards to read and display the centralized student quiz scores (score/total) and lesson progress correctly.
  7. Redirect Fixes: Corrected redirects that pointed to a non-existent index.html to point to login.html.
  8. Code Cleanup: Removed unnecessary debugging console.log statements from teacher.js.

Here is the updated code structure:

<jitProject id="lms-refactor" title="Refactored Learning Management System"> <jitFile type="file" filePath="login.html"> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login</title> <link rel="stylesheet" href="login.css"> </head> <body> <!-- Login Form --> <div class="login-container" id="login-container"> <h2>Login</h2> <input type="text" id="username" placeholder="Enter Username"> <input type="password" id="password" placeholder="Enter Password"> <select id="role"> <option value="">Select Role</option> <option value="teacher">Teacher</option> <option value="student">Junior High School Student</option> <option value="parent">Parent</option> </select> <!-- Container for Teacher ID --> <div id="loginTeacherIdContainer" class="hidden"> <input type="text" id="loginTeacherId" placeholder="Enter Teacher ID Number"> </div> <!-- Container for Student ID --> <div id="loginStudentIdContainer" class="hidden"> <input type="text" id="loginStudentId" placeholder="Enter Student ID Number"> </div> <button onclick="login()">Login</button> <p id="errorMessage" class="error-message"></p> <p>Don't have an account? <a href="#" onclick="showSignup()">Sign up</a></p> </div>
    <!-- Sign Up Form -->
    <div class="signup-container hidden" id="signup-container">
        <h2>Sign Up</h2>
        <input type="text" id="newUsername" placeholder="Choose a Username">
        <input type="password" id="newPassword" placeholder="Choose a Password">
        <select id="newRole">
            <option value="">Select Role</option>
            <option value="teacher">Teacher</option>
            <option value="student">Junior High School Student</option>
            <option value="parent">Parent</option>
        </select>
        <!-- Container for Teacher ID -->
        <div id="signupTeacherIdContainer" class="hidden">
            <input type="text" id="signupTeacherId" placeholder="Enter Teacher ID Number">
        </div>
        <!-- Container for Student Info (Full Name and ID) -->
        <div id="signupStudentInfoContainer" class="hidden">
            <input type="text" id="fullName" placeholder="Enter Full Name">
            <input type="text" id="signupStudentId" placeholder="Enter Student ID Number">
        </div>
        <button onclick="signup()">Sign Up</button>
        <p id="signupMessage" class="signup-message"></p>
        <p>Already have an account? <a href="#" onclick="showLogin()">Log in</a></p>
    </div>

    <script src="login.js"></script>
</body>
</html>
</jitFile> <jitFile type="file" filePath="login.css"> * { margin: 0; padding: 0; box-sizing: border-box; }
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: linear-gradient(135deg, #a2c2e2, #f4f4f4);
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh; /* Use min-height for pages that might grow */
    padding: 20px;
}

.container, /* Generic container for homepage/dashboards */
.login-container,
.signup-container {
    background: #fff;
    width: 100%;
    max-width: 450px; /* Slightly wider for homepage/dashboards */
    padding: 30px;
    border-radius: 12px;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
    text-align: center;
}

h1, h2 { /* Style h1 for homepage/dashboards */
    color: #333;
    margin-bottom: 20px;
    font-size: 24px;
    font-weight: bold;
}

input, select, button {
    width: 100%;
    padding: 15px;
    margin: 10px 0;
    border-radius: 8px;
    border: 1px solid #ddd;
    font-size: 16px;
    outline: none;
    transition: all 0.3s ease;
}

input:focus, select:focus, button:focus {
    border-color: #28a745;
    box-shadow: 0 0 8px rgba(40, 167, 69, 0.3);
}

button {
    background: #28a745;
    color: white;
    border: none;
    cursor: pointer;
    font-weight: bold;
    transition: background 0.3s ease;
}

button:hover {
    background: #218838;
}

.hidden {
    display: none;
}

/* Style for the specific ID containers to ensure consistent margin */
#loginTeacherIdContainer input,
#loginStudentIdContainer input,
#signupTeacherIdContainer input,
#signupStudentInfoContainer input {
    margin-top: 0; /* Inputs inside these divs already have margin */
}

/* Add margin between inputs within the student info container */
#signupStudentInfoContainer input#fullName {
    margin-bottom: 10px;
}


.error-message, .signup-message {
    color: red;
    font-size: 14px;
    margin-top: 10px;
    min-height: 1.2em; /* Reserve space */
}

p {
    font-size: 14px;
    color: #666;
    margin-top: 15px;
}

p a {
    color: #28a745;
    text-decoration: none;
}

p a:hover {
    text-decoration: underline;
}

/* Homepage/Dashboard specific styles */
.welcome-message {
    font-size: 18px;
    margin-bottom: 25px;
    color: #555;
}
</jitFile> <jitFile type="file" filePath="login.js"> // Retrieve users from localStorage function getUsers() { const usersData = localStorage.getItem("users"); if (usersData) { try { return JSON.parse(usersData); } catch (e) { console.error("Error parsing users data from localStorage:", e); // Return empty object or handle error appropriately return {}; } } return {}; // Return empty object if no data found }
// Save users to localStorage
function saveUsers(users) {
    try {
        localStorage.setItem("users", JSON.stringify(users));
    } catch (e) {
        console.error("Error saving users data to localStorage:", e);
        alert("Could not save user data. Progress might not be saved.");
    }
}

function login() {
    const username = document.getElementById("username").value.trim();
    const password = document.getElementById("password").value.trim();
    const role = document.getElementById("role").value;
    const errorMessage = document.getElementById("errorMessage");
    errorMessage.textContent = ''; // Clear previous error

    // Get potential ID values
    const teacherId = document.getElementById("loginTeacherId")?.value.trim();
    const studentId = document.getElementById("loginStudentId")?.value.trim();

    if (!username || !password || !role) {
        errorMessage.textContent = "Please fill in username, password, and select a role.";
        return;
    }

    // Role-specific ID validation
    if (role === 'teacher' && !teacherId) {
        errorMessage.textContent = "Please enter your Teacher ID Number.";
        return;
    }
    if (role === 'student' && !studentId) {
        errorMessage.textContent = "Please enter your Student ID Number.";
        return;
    }

    const users = getUsers();
    const userData = users[username];

    // Check if user exists and credentials match
    let credentialsMatch = userData &&
                           userData.password === password &&
                           userData.role === role;

    // Check ID if applicable
    if (credentialsMatch && role === 'teacher') {
        credentialsMatch = userData.teacherId === teacherId;
    }
    if (credentialsMatch && role === 'student') {
        credentialsMatch = userData.studentId === studentId;
    }


    if (credentialsMatch) {
        // Store user info in sessionStorage
        sessionStorage.setItem('loggedInUsername', username);
        sessionStorage.setItem('loggedInRole', role);
        // Store full name if user is a student (used in student dashboard)
        if (role === 'student' && userData.fullName) {
            sessionStorage.setItem('loggedInFullName', userData.fullName);
        }
         // Optionally store ID if needed later (e.g., display on dashboard)
        if (role === 'teacher') sessionStorage.setItem('loggedInTeacherId', teacherId);
        if (role === 'student') sessionStorage.setItem('loggedInStudentId', studentId);


        // Redirect based on role
        if (role === 'parent') {
            // Parents go directly to the student lookup page
            window.location.href = "parent-access.html";
        } else {
            // Teachers and Students go to the homepage first
            window.location.href = "homepage.html";
        }

    } else {
        errorMessage.textContent = "Incorrect username, password, role, or ID. Please try again.";
    }
}

function signup() {
    const newUsername = document.getElementById("newUsername").value.trim();
    const newPassword = document.getElementById("newPassword").value.trim();
    const newRole = document.getElementById("newRole").value;
    const signupMessage = document.getElementById("signupMessage");
    signupMessage.textContent = ''; // Clear previous message

    // Get potential ID and name values
    const teacherId = document.getElementById("signupTeacherId")?.value.trim();
    const studentId = document.getElementById("signupStudentId")?.value.trim();
    const fullName = document.getElementById("fullName")?.value.trim();


    if (!newUsername || !newPassword || !newRole) {
        signupMessage.textContent = "Please fill in username, password, and select a role.";
        return;
    }

     // Basic password validation
    if (newPassword.length < 4) {
         signupMessage.textContent = "Password must be at least 4 characters long.";
         return;
    }

    // Role-specific field validation
    if (newRole === 'teacher' && !teacherId) {
        signupMessage.textContent = "Teacher ID Number is required for teachers.";
        return;
    }
    if (newRole === 'student' && (!fullName || !studentId)) {
        signupMessage.textContent = "Full Name and Student ID Number are required for students.";
        return;
    }


    const users = getUsers();

    if (users[newUsername]) {
        signupMessage.textContent = "Username already exists. Please choose a different one.";
        return;
    }

    // Store new user in localStorage
    const newUser = { password: newPassword, role: newRole };
    if (newRole === 'teacher') {
        newUser.teacherId = teacherId;
    }
    if (newRole === 'student') {
        newUser.fullName = fullName;
        newUser.studentId = studentId;
        // Initialize progress arrays for new students
        newUser.lessonProgress = [];
        newUser.quizScores = [];
    }
    // Parents don't need extra fields stored here initially
    users[newUsername] = newUser;
    saveUsers(users);

    alert(`Account created successfully for ${newUsername}! Please log in.`);

    // Switch back to login form
    showLogin();
}

function showSignup() {
    document.getElementById("signup-container").classList.remove("hidden");
    document.getElementById("login-container").classList.add("hidden");
    document.getElementById("errorMessage").textContent = '';
    document.getElementById("signupMessage").textContent = '';
    // Reset signup form fields
    document.getElementById("newUsername").value = '';
    document.getElementById("newPassword").value = '';
    document.getElementById("newRole").value = '';
    document.getElementById("signupTeacherId").value = '';
    document.getElementById("fullName").value = '';
    document.getElementById("signupStudentId").value = '';
    // Hide role-specific fields initially
    document.getElementById("signupTeacherIdContainer").classList.add("hidden");
    document.getElementById("signupStudentInfoContainer").classList.add("hidden");
}

function showLogin() {
    document.getElementById("login-container").classList.remove("hidden");
    document.getElementById("signup-container").classList.add("hidden");
    document.getElementById("errorMessage").textContent = '';
    document.getElementById("signupMessage").textContent = '';
     // Reset login form fields
    document.getElementById("username").value = '';
    document.getElementById("password").value = '';
    document.getElementById("role").value = '';
    document.getElementById("loginTeacherId").value = '';
    document.getElementById("loginStudentId").value = '';
    // Hide role-specific fields initially
    document.getElementById("loginTeacherIdContainer").classList.add("hidden");
    document.getElementById("loginStudentIdContainer").classList.add("hidden");
}

// Event listener for role change in LOGIN form
document.getElementById('role')?.addEventListener('change', function() {
    const teacherIdContainer = document.getElementById('loginTeacherIdContainer');
    const studentIdContainer = document.getElementById('loginStudentIdContainer');
    const teacherIdInput = document.getElementById('loginTeacherId');
    const studentIdInput = document.getElementById('loginStudentId');

    // Hide both first
    teacherIdContainer?.classList.add('hidden');
    studentIdContainer?.classList.add('hidden');
    if(teacherIdInput) teacherIdInput.value = ''; // Clear value when hidden
    if(studentIdInput) studentIdInput.value = ''; // Clear value when hidden


    if (this.value === 'teacher') {
        teacherIdContainer?.classList.remove('hidden');
    } else if (this.value === 'student') {
        studentIdContainer?.classList.remove('hidden');
    }
});


// Event listener for role change in SIGNUP form
document.getElementById('newRole')?.addEventListener('change', function() {
    const teacherIdContainer = document.getElementById('signupTeacherIdContainer');
    const studentInfoContainer = document.getElementById('signupStudentInfoContainer');
    const teacherIdInput = document.getElementById('signupTeacherId');
    const studentIdInput = document.getElementById('signupStudentId');
    const fullNameInput = document.getElementById('fullName');


    // Hide all role-specific containers first
    teacherIdContainer?.classList.add('hidden');
    studentInfoContainer?.classList.add('hidden');

    // Clear values when hidden
    if(teacherIdInput) teacherIdInput.value = '';
    if(studentIdInput) studentIdInput.value = '';
    if(fullNameInput) fullNameInput.value = '';


    if (this.value === 'teacher') {
        teacherIdContainer?.classList.remove('hidden');
    } else if (this.value === 'student') {
        studentInfoContainer?.classList.remove('hidden');
    }
});


// Clear session storage on login page load and ensure correct form is shown
document.addEventListener('DOMContentLoaded', () => {
    // Only run login page specific logic if login container exists
    if (document.getElementById('login-container')) {
        sessionStorage.clear(); // Clear all session storage on login page load
        showLogin(); // Ensure login form is shown by default and fields are reset/hidden
    }
});
</jitFile> <jitFile type="file" filePath="homepage.html"> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Welcome</title> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #e2f0d9, #f4f4f4); /* Light green gradient */ display: flex; justify-content: center; align-items: center; height: 100vh; padding: 20px; text-align: center; color: #333; margin: 0; }
        .welcome-container {
            background: #fff;
            padding: 40px;
            border-radius: 12px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
            max-width: 500px;
            width: 100%;
        }

        h1 {
            color: #28a745; /* Green color */
            margin-bottom: 15px;
            font-size: 28px;
        }

        p {
            font-size: 18px;
            margin-bottom: 30px;
            line-height: 1.6;
        }

        .dashboard-button {
            display: inline-block;
            padding: 15px 30px;
            background: #28a745;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 18px;
            font-weight: bold;
            text-decoration: none;
            transition: background 0.3s ease;
        }

        .dashboard-button:hover {
            background: #218838;
        }

    </style>
</head>
<body>
    <div class="welcome-container">
        <h1 id="welcome-message">Welcome!</h1>
        <p>You have successfully logged in. Click the button below to proceed to your dashboard.</p>
        <button id="dashboard-link" class="dashboard-button">Go to Dashboard</button>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const username = sessionStorage.getItem('loggedInUsername');
            const role = sessionStorage.getItem('loggedInRole');
            const welcomeMessage = document.getElementById('welcome-message');
            const dashboardLink = document.getElementById('dashboard-link');

            // If no user info found, or if role is parent (shouldn't be here), redirect to login
            if (!username || !role || role === 'parent') {
                alert('You need to log in first.');
                window.location.href = 'login.html';
                return;
            }

            // Personalize welcome message
            welcomeMessage.textContent = `Welcome, ${username}!`;

            // Determine dashboard URL (Only Teacher or Student should reach here)
            let dashboardUrl = '';
            if (role === 'teacher') {
                dashboardUrl = 'teacher.html';
            } else if (role === 'student') {
                dashboardUrl = 'student.html';
            } else {
                // Fallback if role is unexpected (redirect to login)
                console.error('Unexpected user role on homepage:', role);
                alert('Invalid user role detected.');
                sessionStorage.clear(); // Clear session
                window.location.href = 'login.html';
                return;
            }

            // Set button click action
            dashboardLink.onclick = () => {
                window.location.href = dashboardUrl;
            };
        });
    </script>
</body>
</html>
</jitFile> <jitFile type="file" filePath="teacher.html"> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Teacher Dashboard</title> <link rel="stylesheet" href="teacher.css"> </head> <body>
    <div class="navbar">
        <h1>Teacher Dashboard</h1>
    </div>

    <div class="container">
        <div class="button-container">
            <button class="btn" id="createLessonBtn">Create Lesson</button>
            <button class="btn" id="createQuizBtn">Make Quiz</button>
            <button class="btn" id="manageScoresBtn">Manage Scores & Grades</button>
            <button class="btn" id="deleteLessonBtn">Delete Lesson</button>
            <button class="btn" id="deleteQuizBtn">Delete Quiz</button>
        </div>

        <h3>Created Lessons</h3>
        <div id="createdLessons"></div>

        <h3>Created Quizzes</h3>
        <div id="createdQuizzes"></div>
    </div>

    <!-- Lesson Modal (Create/Edit) -->
    <div id="lessonModal" class="modal">
        <div class="modal-content">
            <span class="close" data-modal-id="lessonModal">&times;</span>
            <h2 id="lessonModalTitle">Create Lesson</h2>
            <form id="lessonForm">
                <input type="hidden" id="editLessonIndex" value="-1">
                <label for="lessonTitle">Lesson Title:</label>
                <input type="text" id="lessonTitle" name="lessonTitle" required><br><br>
                <label for="lessonContent">Lesson Content:</label>
                <textarea id="lessonContent" name="lessonContent" rows="4" required></textarea><br><br>
                <button type="submit" id="lessonSubmitBtn" class="btn">Create Lesson</button>
            </form>
        </div>
    </div>

    <!-- Quiz Modal (Create/Edit) -->
    <div id="quizModal" class="modal">
        <div class="modal-content large">
            <span class="close" data-modal-id="quizModal">&times;</span>
            <h2 id="quizModalTitle">Create Quiz</h2>
            <form id="quizForm">
                 <input type="hidden" id="editQuizIndex" value="-1">
                <label for="quizType">Quiz Type:</label>
                <select id="quizType" name="quizType" required>
                    <option value="multiple-choice">Multiple Choice</option>
                    <option value="identification">Identification</option>
                </select><br><br>
                <label for="quizTitle">Quiz Title:</label>
                <input type="text" id="quizTitle" name="quizTitle" required><br><br>
                <div id="questionsContainer"></div>
                <button type="button" class="btn" id="addQuestionBtn">Add Question</button><br><br>
                <button type="submit" id="quizSubmitBtn" class="btn">Create Quiz</button>
            </form>
        </div>
    </div>

    <!-- Delete Modal (Handles both Lessons and Quizzes) -->
    <div id="deleteModal" class="modal">
        <div class="modal-content">
            <span class="close" data-modal-id="deleteModal">&times;</span>
            <h2>Delete Item</h2> <!-- Generic Title -->
            <label for="deleteType">Item Type:</label> <!-- Generic Label -->
            <select id="deleteType"> <!-- Type Select Re-added -->
                <option value="lesson">Lesson</option>
                <option value="quiz">Quiz</option>
            </select><br><br>
            <label for="deleteChoice">Select Item to Delete:</label> <!-- Generic Label -->
            <select id="deleteChoice"></select><br><br>
            <button id="deleteBtn" class="btn delete">Delete</button>
        </div>
    </div>

    <!-- Manage Scores Modal -->
    <div id="manageScoresModal" class="modal">
        <div class="modal-content large">
             <span class="close" data-modal-id="manageScoresModal">&times;</span>
             <h2>Manage Scores and Grades</h2>
             <div class="manage-scores-container">
                 <label for="quizSelectForScores">Select Quiz:</label>
                 <select id="quizSelectForScores">
                     <option value="">-- Select a Quiz --</option>
                     <!-- Options populated by JS -->
                 </select>

                 <div id="studentScoresDisplay" class="scores-display-area">
                     <p class="no-scores-message">Select a quiz to view student scores.</p>
                     <!-- Table will be inserted here by JS -->
                 </div>
             </div>
        </div>
    </div>


    <!-- Performance Analytics Button -->
    <button id="analyticsBtn" class="analytics-btn">View Performance & Analytics</button>

    <!-- Performance Analytics Fullscreen Modal -->
    <div id="analyticsModal" class="modal fullscreen">
        <div class="modal-content">
            <h2>Teacher Performance & Analytics</h2>
            <div class="analytics-section">
                <h3>Overview</h3>
                <p><strong>Lessons Created:</strong> <span id="lessonCount">0</span></p>
                <p><strong>Quizzes Created:</strong> <span id="quizCount">0</span></p>
            </div>
            <div class="analytics-section">
                 <h3>Class Performance (Average Score Across All Quizzes Taken)</h3>
                 <p>Average Quiz Score: <span id="averageQuizScore">N/A</span></p>
            </div>
            <div class="modal-navigation">
                <button id="modalDashboardBtn" class="modal-nav-btn dashboard">Back to Dashboard</button>
                <button id="modalHomeBtn" class="modal-nav-btn home">Homepage</button>
                <button id="modalLogoutBtn" class="modal-nav-btn logout">Logout</button>
            </div>
        </div>
    </div>
    <!-- Include login.js for getUsers function -->
    <script src="login.js"></script>
    <script src="teacher.js"></script>
</body>
</html>
</jitFile> <jitFile type="file" filePath="teacher.css"> body { font-family: Arial, sans-serif; background-color: #f2f2f2; padding: 0 20px 80px 20px; /* Remove top padding, ensure bottom padding for fixed button */ margin: 0; line-height: 1.6; } /* Prevent body scroll when fullscreen modal is open */ body.modal-open { overflow: hidden; }
.navbar {
    background-color: #4CAF50;
    color: white;
    padding:*_
Updated files
v1
i need the full code