JIT
Add Student and Teacher IDs to Login Signup
make a space to login page for student id number and as well as when i sign up as a student, and same as the teacher make a space their teacher id number and as well when they sign up on this code: <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> <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 Full Name, hidden by default --> <div id="fullNameContainer" class="hidden"> <input type="text" id="fullName" placeholder="Enter Full Name"> </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> * { 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 full name container to ensure consistent margin */ #fullNameContainer input { margin-top: 10px; /* Adjust if needed */ } .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; } // 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 if (!username || !password || !role) { errorMessage.textContent = "Please fill in all fields and select a role."; return; } const users = getUsers(); const userData = users[username]; // Check if user exists and credentials match if (userData && userData.password === password && userData.role === role) { // 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); } // Redirect to the homepage window.location.href = "homepage.html"; } else { errorMessage.textContent = "Incorrect username, password, or role. 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 fullNameInput = document.getElementById("fullName"); const fullName = fullNameInput.value.trim(); const signupMessage = document.getElementById("signupMessage"); signupMessage.textContent = ''; // Clear previous message if (!newUsername || !newPassword || !newRole) { signupMessage.textContent = "Please fill in all fields and select a role."; return; } // Check if full name is required and provided if (newRole === 'student' && !fullName) { signupMessage.textContent = "Full Name is required for students."; return; } // Basic validation if (newPassword.length < 4) { signupMessage.textContent = "Password must be at least 4 characters long."; 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 === 'student') { newUser.fullName = fullName; // Add fullName only for students } 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 and hide full name initially document.getElementById("newUsername").value = ''; document.getElementById("newPassword").value = ''; document.getElementById("newRole").value = ''; document.getElementById("fullName").value = ''; document.getElementById("fullNameContainer").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 = ''; } // Event listener for role change in signup form document.getElementById('newRole')?.addEventListener('change', function() { // Add null check for safety const fullNameContainer = document.getElementById('fullNameContainer'); if (this.value === 'student') { fullNameContainer?.classList.remove('hidden'); } else { fullNameContainer?.classList.add('hidden'); const fullNameInput = document.getElementById('fullName'); if (fullNameInput) fullNameInput.value = ''; // Clear full name if role changes away from student } }); // 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.removeItem('loggedInUsername'); sessionStorage.removeItem('loggedInRole'); sessionStorage.removeItem('loggedInFullName'); // Clear full name too showLogin(); // Ensure login form is shown by default } });

Okay, I will modify the HTML, CSS, and JavaScript to include ID number fields for students and teachers in both the login and signup forms.

Now, the login and signup forms will dynamically show/hide the appropriate ID number fields based on the selected role (Teacher or Student). The ID numbers are required for login and signup for these roles and are stored/validated accordingly.

Updated files
v1
create a parent dashboard that can tract the students score in quiz and their progress on lessons if they red it, the parent must put the students name and id number before proceeding to the dashboard

Okay, let's create the parent access verification page and the parent dashboard page.

This involves:

  1. parent-access.html: A page where the parent enters the student's full name and ID number.
  2. parent-dashboard.html: The page displaying the student's scores and lesson progress, accessible only after successful verification.
  3. parent.css: Styles for these new pages.
  4. parent.js: JavaScript logic for verification on the access page and data display on the dashboard.

We'll assume the student data (scores, lesson progress) is stored within the student's user object in localStorage. For demonstration, we'll add some sample data structure to login.js when a student signs up and mock data retrieval in parent.js.

First, let's slightly modify login.js to include placeholders for scores and progress when a student signs up.

Now, let's create the parent-specific files.

Explanation:

  1. login.js Update:
    • When a student signs up, sample quizScores and lessonProgress arrays are added to their user object in localStorage.
    • When a parent logs in successfully, they are now redirected to parent-access.html instead of homepage.html.
  2. parent-access.html:
    • Simple form asking for the student's full name and ID.
    • Uses parent.css and parent.js.
    • Includes login.js to access the getUsers() function.
  3. parent-dashboard.html:
    • Structure to display student name/ID, quiz scores, and lesson progress.
    • Placeholders (<span> tags and <ul> lists) will be filled by JavaScript.
    • Includes links to look up another student or log out.
    • Uses parent.css and parent.js.
    • Includes login.js to access the getUsers() function.
  4. parent.css:
    • Provides styling, borrowing heavily from login.css but with a slightly different color theme (#c82333 red) and layout adjustments for the dashboard.
  5. parent.js:
    • verifyStudent(): Called on parent-access.html. It gets the input values, searches the users data from localStorage for a student matching both name and ID. If found, it stores the student's username (the key in the users object) in sessionStorage and redirects to the dashboard. Otherwise, it shows an error.
    • populateDashboard(): Called when parent-dashboard.html loads. It checks sessionStorage for the viewingStudentUsername. If missing, it redirects back to the access page. If present, it retrieves the full student data using the username, and dynamically updates the HTML to show the name, ID, scores, and lesson progress.
    • logoutParent(): Clears the relevant session storage and redirects to the main login page.
    • The script checks which page it's on before running populateDashboard to avoid errors.

Now, when a parent logs in, they'll be directed to parent-access.html. After entering a valid student name and ID, they'll see the parent-dashboard.html populated with that student's (mock) data.*

Updated files
v2
connect this code on the student dashboard code: <!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> <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>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="student.js"></script> </body> </html> /* 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; } .lesson h4, .quiz h4 { margin-top: 0; color: #555; } .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 { list-style: none; padding: 0; max-height: 35vh; /* Adjust max height relative to viewport */ overflow-y: auto; } #quizScoresList li { 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 */ } #quizScoresList li strong { color: #333; } #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); } document.addEventListener('DOMContentLoaded', () => { // --- Check if user is logged in --- const loggedInUsername = sessionStorage.getItem('loggedInUsername'); const loggedInRole = sessionStorage.getItem('loggedInRole'); if (!loggedInUsername || !loggedInRole || loggedInRole !== 'student') { alert('Access denied. Please log in as a student.'); window.location.href = 'login.html'; // Redirect if not a student return; } // --- End Login Check --- const createdLessonsDiv = document.getElementById('createdLessons'); const createdQuizzesDiv = document.getElementById('createdQuizzes'); // Parent container for quizzes 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 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'); const storageKeys = { lessons: 'createdLessons', // Global lessons quizzes: 'createdQuizzes', // Global quizzes // Key for this specific student's results, using their username studentQuizResults: `studentQuizResults_${loggedInUsername}`, // Key for this specific student's last access time lastAccessed: `studentLastAccessed_${loggedInUsername}` }; // --- Utility Functions --- // 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 (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 saving data to localStorage for key:", key, e); } }; // --- Track Last Accessed --- function recordLastAccessed() { const now = new Date(); localStorage.setItem(storageKeys.lastAccessed, now.toISOString()); } // --- Lesson Display --- function updateCreatedLessons() { const lessons = getData(storageKeys.lessons); createdLessonsDiv.innerHTML = ''; if (lessons.length === 0) { createdLessonsDiv.innerHTML = '<p>No lessons available.</p>'; return; } lessons.forEach((lesson) => { const lessonDiv = document.createElement('div'); lessonDiv.classList.add('lesson'); // Basic validation const title = lesson.title || 'Untitled Lesson'; const content = lesson.content || 'No content.'; lessonDiv.innerHTML = `<h4>${title}</h4><p>${content}</p>`; createdLessonsDiv.appendChild(lessonDiv); }); } // --- Quiz Display and Taking Logic --- function updateCreatedQuizzes() { console.log("Updating created quizzes display for student:", loggedInUsername); const quizzes = getData(storageKeys.quizzes); // Get results specific to this student const results = getObjectData(storageKeys.studentQuizResults); createdQuizzesDiv.innerHTML = ''; // Clear previous content if (quizzes.length === 0) { createdQuizzesDiv.innerHTML = '<p>No quizzes available.</p>'; checkAndEnforceQuizCompletion(); // Check even if no quizzes return; } quizzes.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 quizDiv = document.createElement('div'); quizDiv.classList.add('quiz'); quizDiv.id = `quiz-${index}`; // Check if this student has taken this quiz (using the student-specific results) const hasTaken = results[index] !== undefined; const resultData = results[index]; // Get the result data if it exists console.log(`Quiz Index: ${index}, Title: ${quiz.quizTitle}, Has Taken: ${hasTaken}`); quizDiv.innerHTML = ` <h4>${quiz.quizTitle || 'Untitled Quiz'}</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} / ${resultData.total}</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 quizzes = getData(storageKeys.quizzes); // Validate quiz index and data if (quizIndex === undefined || !quizzes[quizIndex] || !Array.isArray(quizzes[quizIndex].questions)) { console.error(`Invalid quiz index or data for index ${quizIndex}`); alert("Error: Could not load quiz data."); return; } const quiz = quizzes[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}"]`); if (otherTakeButton && !otherTakeButton.disabled) { // 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 quizzes = getData(storageKeys.quizzes); // Validate quiz index and data if (quizIndex === undefined || !quizzes[quizIndex] || !Array.isArray(quizzes[quizIndex].questions)) { console.error(`Invalid quiz index or data for submission: ${quizIndex}`); alert("Error: Could not submit quiz data."); return; } const quiz = quizzes[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; const totalQuestionsInQuiz = quiz.questions.length; // Total questions defined in the quiz data // 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'); // Also remove potential line-through from previous incorrect answers 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 question *defined in the quiz data* quiz.questions.forEach((question, qIndex) => { // Skip if question was invalid during startQuiz (shouldn't happen if startQuiz filters) if (!question || typeof question.questionText === 'undefined') { console.warn(`Skipping evaluation for invalid question data at qIndex ${qIndex} in quiz ${quizIndex}`); return; } let studentAnswer = null; const correctAnswer = question.correctAnswer; // Get correct answer from quiz data // Find the corresponding question element in the DOM based on the loop index (qIndex) const questionElement = questionsArea.querySelector(`.quiz-question:nth-child(${qIndex + 1})`); const questionNumberElement = questionElement ? questionElement.querySelector('p strong') : null; let isCorrect = false; if (!questionElement || !questionNumberElement) { console.warn(`Could not find question element in DOM for 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; // Mark as unanswered if empty } else if (correctAnswer !== undefined && correctAnswer !== null && studentAnswer.toLowerCase() === String(correctAnswer).toLowerCase()) { score++; isCorrect = true; } } else if (quiz.quizType === 'multiple-choice') { const checkedRadio = questionElement.querySelector(`input[type="radio"]:checked`); if (!checkedRadio) { allAnswered = false; // Mark as unanswered if no radio is checked } else { studentAnswer = checkedRadio.value; // Value was set during startQuiz // Compare student's answer value with the correct answer value if (studentAnswer === String(correctAnswer)) { // Ensure comparison is consistent (e.g., string vs string) score++; isCorrect = true; } } } }); // End of quiz.questions.forEach for validation // --- Check if all questions were answered --- if (!allAnswered) { alert('Please answer all questions before submitting.'); // Re-enable inputs if validation failed questionsArea.querySelectorAll('input[type="text"], input[type="radio"]').forEach(input => input.disabled = false); 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 to apply feedback styles quiz.questions.forEach((question, qIndex) => { const questionElement = questionsArea.querySelector(`.quiz-question:nth-child(${qIndex + 1})`); if (!questionElement) return; // Skip if element not found const questionNumberElement = questionElement.querySelector('p strong'); const correctAnswer = question.correctAnswer; let studentAnswer = null; // Re-fetch the final answer for feedback 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'); // Show correct answer text if (correctAnswer !== undefined && correctAnswer !== null) { const correctAnswerSpan = document.createElement('span'); correctAnswerSpan.classList.add('correct-answer-text'); correctAnswerSpan.textContent = `Correct answer: ${correctAnswer}`; // Insert after the input field 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'); questionNumberElement.appendChild(feedbackMark); } }); // End of feedback loop // --- Display Final Score and Save --- scoreArea.innerHTML = `<h3>Your Score: ${score} / ${totalQuestionsInQuiz}</h3>`; 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 using the total questions from the quiz data saveQuizResult(quizIndex, quiz.quizTitle, score, totalQuestionsInQuiz); checkAndEnforceQuizCompletion(); // Update analytics button status } function saveQuizResult(quizIndex, quizTitle, score, totalQuestions) { // Get the current results for THIS student const results = getObjectData(storageKeys.studentQuizResults); results[quizIndex] = { title: quizTitle || 'Untitled Quiz', // Use fallback title score: score, total: totalQuestions, // Use the actual total number of questions timestamp: new Date().toISOString() }; // Save the updated results back under the student-specific key setData(storageKeys.studentQuizResults, results); console.log("Quiz result saved for index:", quizIndex, "for student:", loggedInUsername, results[quizIndex]); } // --- Quiz Completion Enforcement --- function checkAndEnforceQuizCompletion() { const quizzes = getData(storageKeys.quizzes); // Get results specific to this student const results = getObjectData(storageKeys.studentQuizResults); let allValidQuizzesTaken = true; // Ensure quizzes is an array before checking length const numQuizzes = Array.isArray(quizzes) ? quizzes.length : 0; if (numQuizzes === 0) { allValidQuizzesTaken = true; // No quizzes to take } else { for (let i = 0; i < numQuizzes; i++) { // Check if the quiz itself is valid before checking results const quiz = quizzes[i]; if (!quiz || typeof quiz.quizTitle === 'undefined' || !Array.isArray(quiz.questions)) { console.warn(`Skipping invalid quiz index ${i} during completion check.`); continue; // Skip invalid quiz entries in the completion check } // Check if THIS student has taken this VALID quiz if (results[i] === undefined) { 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() { // Get last accessed time for this student const lastAccessedISO = localStorage.getItem(storageKeys.lastAccessed); lastAccessedSpan.textContent = lastAccessedISO ? new Date(lastAccessedISO).toLocaleString() : 'Not recorded yet.'; // Get results specific to this student const results = getObjectData(storageKeys.studentQuizResults); const quizIndices = Object.keys(results); // Indices of TAKEN quizzes by this student quizScoresListUl.innerHTML = ''; // Clear previous list const quizzes = getData(storageKeys.quizzes); // All available quizzes (for titles) if (quizIndices.length === 0) { quizScoresListUl.innerHTML = '<li>No quizzes taken yet.</li>'; overallGradeSpan.textContent = 'N/A'; return; } let totalScore = 0; let totalPossibleScore = 0; // Sort taken quiz indices numerically for consistent display order quizIndices.sort((a, b) => parseInt(a) - parseInt(b)); quizIndices.forEach(index => { const result = results[index]; // Ensure result has expected properties before calculating if (result && typeof result.score === 'number' && typeof result.total === 'number') { // Get title from the main quizzes list if possible, otherwise use title from result or fallback const quizTitle = (quizzes[index] && quizzes[index].quizTitle) ? quizzes[index].quizTitle : (result.title || `Quiz ${parseInt(index) + 1}`); const listItem = document.createElement('li'); const percentage = result.total > 0 ? ((result.score / result.total) * 100).toFixed(1) : 0; listItem.innerHTML = `<strong>${quizTitle}:</strong> ${result.score} / ${result.total} (${percentage}%)`; quizScoresListUl.appendChild(listItem); totalScore += result.score; totalPossibleScore += result.total; } else { console.warn(`Invalid result data found for index ${index} in student results:`, result); } }); // Calculate overall grade based on the quizzes actually taken and displayed overallGradeSpan.textContent = totalPossibleScore > 0 ? `${((totalScore / totalPossibleScore) * 100).toFixed(1)}%` : '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 --- 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 });

Okay, let's integrate the student dashboard with the parent tracking system. This involves modifying student.js to update the shared student data in localStorage that the parent dashboard reads.

We'll make the following key changes:

  1. student.js - Saving Quiz Results: Modify saveQuizResult to update the quizScores array within the main student user object stored in localStorage (the one used by login.js and parent.js).
  2. student.js - Tracking Lesson Progress: Add functionality for students to mark lessons as "read" and update the lessonProgress array in their main user object.
  3. student.js - Reading Data: Adjust functions like updateCreatedQuizzes, checkAndEnforceQuizCompletion, and populateAnalyticsData to read quiz taken status and scores directly from the main student user object.
  4. student.html & student.css: Add elements and styles for the "Mark as Read" functionality.

First, let's ensure login.js initializes the arrays properly if they don't exist when a student logs in (though signup already does this, it's good practice). Self-correction: This check is better placed within student.js when data is accessed, as the student might log in without having signed up in the same session.

Modified Files:

<jitProject id="student-parent-integration" title="Integrate Student and Parent Dashboards"> <jitFile type="file" filePath="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>
</jitFile> <jitFile type="file" filePath="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);
}
</jitFile> <jitFile type="file" filePath="student.js"> document.addEventListener('DOMContentLoaded', () => { // --- Check if user is logged in --- const loggedInUsername = sessionStorage.getItem('loggedInUsername'); const loggedInRole = sessionStorage.getItem('loggedInRole');
    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

    // --- 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');

            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'; // Or 'completed' if you prefer
        } 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;

            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;
                    if (radio.value === String(correctAnswer)) choiceLabel.classList.add('correct-answer-highlight');
                    if (radio.checked && !isCorrect) {
Updated files
v3
give me student.js code of this

Okay, here is the complete student.js code, incorporating the integration with the parent dashboard data stored in the main user object.

javascript document.addEventListener('DOMContentLoaded', () => { // --- Check if user is logged in --- const loggedInUsername = sessionStorage.getItem('loggedInUsername'); const loggedInRole = sessionStorage.getItem('loggedInRole');

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

});

Key Changes Implemented:

  1. Data Source: All functions (updateCreatedQuizzes, submitQuiz, saveQuizResult, checkAndEnforceQuizCompletion, populateAnalyticsData) now read from and write to the student's specific data object within the main users object in localStorage (accessed via getCurrentStudentData, getUsers, saveUsers).
  2. getCurrentStudentData: Added a helper function to reliably get the current student's data and initialize quizScores and lessonProgress arrays if they are missing. Includes error handling and logout if data is corrupt.
  3. Lesson Tracking: Added markLessonAsRead function and event listener. updateCreatedLessons now checks the student's lessonProgress array to set the button state. populateAnalyticsData now displays lesson progress.
  4. Quiz Score Saving: saveQuizResult now saves the quizName and score (as a percentage) into the studentData.quizScores array. It updates if the quiz was taken before, otherwise adds a new entry.
  5. Quiz Score Display: updateCreatedQuizzes and populateAnalyticsData display the percentage score stored in studentData.quizScores.
  6. Completion Check: checkAndEnforceQuizCompletion now iterates through the valid global quizzes and checks against the student's quizScores array (by quizName) to determine if all have been taken.
  7. Overall Grade: Calculated in populateAnalyticsData as the average of the percentage scores of all quizzes taken by the student.
  8. Dependencies: Added checks to ensure getUsers and saveUsers (from login.js) are available. Remember to include <script src="login.js"></script> before <script src="student.js"></script> in your student.html.*