make the student username and score appear on teachers dashboard ( manage score and grade ) after they took the quiz created by the teacher on this code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Teacher Dashboard</title>
<link rel="stylesheet" href="teacher.css">
</head>
<body>
<div class="navbar">
<h1>Teacher Dashboard</h1>
</div>
<div class="container">
<div class="button-container">
<button class="btn" id="createLessonBtn">Create Lesson</button>
<button class="btn" id="createQuizBtn">Make Quiz</button>
<button class="btn" id="manageScoresBtn">Manage Scores & Grades</button>
<button class="btn" id="deleteLessonBtn">Delete Lesson</button>
<button class="btn" id="deleteQuizBtn">Delete Quiz</button> <!-- Delete Quiz Button Re-added -->
</div>
<h3>Created Lessons</h3>
<div id="createdLessons"></div>
<h3>Created Quizzes</h3>
<div id="createdQuizzes"></div>
</div>
<!-- Lesson Modal (Create/Edit) -->
<div id="lessonModal" class="modal">
<div class="modal-content">
<span class="close" data-modal-id="lessonModal">×</span>
<h2 id="lessonModalTitle">Create Lesson</h2>
<form id="lessonForm">
<input type="hidden" id="editLessonIndex" value="-1">
<label for="lessonTitle">Lesson Title:</label>
<input type="text" id="lessonTitle" name="lessonTitle" required><br><br>
<label for="lessonContent">Lesson Content:</label>
<textarea id="lessonContent" name="lessonContent" rows="4" required></textarea><br><br>
<button type="submit" id="lessonSubmitBtn" class="btn">Create Lesson</button>
</form>
</div>
</div>
<!-- Quiz Modal (Create/Edit) -->
<div id="quizModal" class="modal">
<div class="modal-content large">
<span class="close" data-modal-id="quizModal">×</span>
<h2 id="quizModalTitle">Create Quiz</h2>
<form id="quizForm">
<input type="hidden" id="editQuizIndex" value="-1">
<label for="quizType">Quiz Type:</label>
<select id="quizType" name="quizType" required>
<option value="multiple-choice">Multiple Choice</option>
<option value="identification">Identification</option>
</select><br><br>
<label for="quizTitle">Quiz Title:</label>
<input type="text" id="quizTitle" name="quizTitle" required><br><br>
<div id="questionsContainer"></div>
<button type="button" class="btn" id="addQuestionBtn">Add Question</button><br><br>
<button type="submit" id="quizSubmitBtn" class="btn">Create Quiz</button>
</form>
</div>
</div>
<!-- Delete Modal (Handles both Lessons and Quizzes) -->
<div id="deleteModal" class="modal">
<div class="modal-content">
<span class="close" data-modal-id="deleteModal">×</span>
<h2>Delete Item</h2> <!-- Generic Title -->
<label for="deleteType">Item Type:</label> <!-- Generic Label -->
<select id="deleteType"> <!-- Type Select Re-added -->
<option value="lesson">Lesson</option>
<option value="quiz">Quiz</option>
</select><br><br>
<label for="deleteChoice">Select Item to Delete:</label> <!-- Generic Label -->
<select id="deleteChoice"></select><br><br>
<button id="deleteBtn" class="btn delete">Delete</button>
</div>
</div>
<!-- Manage Scores Modal -->
<div id="manageScoresModal" class="modal">
<div class="modal-content large">
<span class="close" data-modal-id="manageScoresModal">×</span>
<h2>Manage Scores and Grades</h2>
<div class="manage-scores-container">
<label for="quizSelectForScores">Select Quiz:</label>
<select id="quizSelectForScores">
<option value="">-- Select a Quiz --</option>
</select>
<div id="studentScoresDisplay" class="scores-display-area">
<p>Select a quiz to view student scores.</p>
</div>
</div>
</div>
</div>
<!-- Performance Analytics Button -->
<button id="analyticsBtn" class="analytics-btn">View Performance & Analytics</button>
<!-- Performance Analytics Fullscreen Modal -->
<div id="analyticsModal" class="modal fullscreen">
<div class="modal-content">
<h2>Teacher Performance & Analytics</h2>
<div class="analytics-section">
<h3>Overview</h3>
<p><strong>Lessons Created:</strong> <span id="lessonCount">0</span></p>
<p><strong>Quizzes Created:</strong> <span id="quizCount">0</span></p>
</div>
<div class="analytics-section">
<h3>Class Performance (Example)</h3>
<p>Average Quiz Score: <span id="averageQuizScore">N/A</span></p>
</div>
<div class="modal-navigation">
<button id="modalDashboardBtn" class="modal-nav-btn dashboard">Back to Dashboard</button>
<button id="modalHomeBtn" class="modal-nav-btn home">Homepage</button>
<button id="modalLogoutBtn" class="modal-nav-btn logout">Logout</button>
</div>
</div>
</div>
<script src="teacher.js"></script>
</body>
</html>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
padding: 0 20px 80px 20px; /* Remove top padding, ensure bottom padding for fixed button */
margin: 0;
line-height: 1.6;
}
/* Prevent body scroll when fullscreen modal is open */
body.modal-open {
overflow: hidden;
}
.navbar {
background-color: #4CAF50;
color: white;
padding: 15px 20px; /* Slightly more padding */
margin-bottom: 25px; /* More space */
border-radius: 0 0 5px 5px; /* Rounded bottom corners */
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.navbar h1 {
margin: 0;
text-align: center;
font-size: 1.8em;
}
.container {
background-color: #fff;
padding: 25px;
border-radius: 8px; /* More rounded */
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
max-width: 1000px; /* Wider container */
margin: 0 auto 20px auto; /* Center container, reduce bottom margin */
}
.hidden {
display: none;
}
/* --- Standard Modal Styles --- */
.modal:not(.fullscreen) { /* Apply only to non-fullscreen modals */
display: none;
position: fixed;
z-index: 100;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5); /* Darker overlay */
padding-top: 50px;
}
.modal:not(.fullscreen) .modal-content {
background-color: #fff;
margin: 3% auto; /* Adjust vertical margin */
padding: 25px 30px; /* More padding */
border: 1px solid #ccc;
border-radius: 8px;
width: 90%;
max-width: 650px; /* Default max-width */
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
position: relative; /* For close button */
animation-name: animatetop;
animation-duration: 0.4s;
}
/* Larger modal variant */
.modal:not(.fullscreen) .modal-content.large {
max-width: 850px;
}
@keyframes animatetop {
from {top: -300px; opacity: 0}
to {top: 0; opacity: 1}
}
.close {
color: #aaa;
position: absolute; /* Position relative to modal-content */
top: 10px;
right: 15px;
font-size: 30px;
font-weight: bold;
line-height: 1;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
/* --- Fullscreen Modal Styles --- */
.modal.fullscreen {
display: none;
position: fixed;
z-index: 1001;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #f8f9fa; /* Light background */
}
.modal.fullscreen .modal-content {
background-color: transparent;
margin: 0;
padding: 40px; /* More padding */
border: none;
width: 100%;
height: 100%;
max-width: none;
border-radius: 0;
box-shadow: none;
position: relative;
overflow-y: auto;
box-sizing: border-box;
}
.modal.fullscreen h2 {
text-align: center;
color: #6f42c1; /* Keep purple for analytics title */
margin-top: 10px;
margin-bottom: 40px; /* More space */
font-size: 2em; /* Larger title */
border-bottom: none; /* Remove border */
}
.modal.fullscreen .analytics-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 8px;
background-color: #fff; /* White background for sections */
max-width: 900px;
margin-left: auto;
margin-right: auto;
}
.modal.fullscreen .analytics-section:last-of-type {
border-bottom: 1px solid #e0e0e0; /* Keep border */
}
.modal.fullscreen .analytics-section h3 {
color: #555;
margin-top: 0;
margin-bottom: 15px;
font-size: 1.4em;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
}
.modal.fullscreen .analytics-section p {
font-size: 1.1em;
margin-bottom: 10px;
}
.modal.fullscreen .analytics-section span {
font-weight: normal;
color: #333;
}
/* Styles for Navigation Buttons inside Fullscreen Modal */
.modal.fullscreen .modal-navigation {
margin-top: 40px;
padding-top: 30px;
border-top: 1px solid #ccc;
text-align: center;
display: flex;
justify-content: center;
gap: 25px;
max-width: 900px;
margin-left: auto;
margin-right: auto;
}
.modal.fullscreen .modal-nav-btn {
padding: 12px 30px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 1.1em;
font-weight: bold;
transition: background-color 0.3s ease, transform 0.2s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.modal.fullscreen .modal-nav-btn.dashboard {
background-color: #ffc107;
color: #333;
}
.modal.fullscreen .modal-nav-btn.dashboard:hover {
background-color: #e0a800;
transform: translateY(-1px);
}
.modal.fullscreen .modal-nav-btn.home {
background-color: #17a2b8;
color: white;
}
.modal.fullscreen .modal-nav-btn.home:hover {
background-color: #138496;
transform: translateY(-1px);
}
.modal.fullscreen .modal-nav-btn.logout {
background-color: #dc3545;
color: white;
}
.modal.fullscreen .modal-nav-btn.logout:hover {
background-color: #c82333;
transform: translateY(-1px);
}
/* --- Other Styles --- */
.button-container {
margin-bottom: 30px;
text-align: center; /* Center buttons */
}
.btn {
padding: 12px 25px; /* Larger buttons */
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em; /* Adjust font size */
margin: 5px; /* Use margin for spacing */
transition: background-color 0.3s ease, box-shadow 0.2s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.btn:hover {
background-color: #45a049;
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.btn.delete { /* Consistent naming */
background-color: #f44336;
}
.btn.delete:hover {
background-color: #da190b;
}
.btn.edit { /* Style for edit buttons */
background-color: #ffc107;
color: #333;
padding: 5px 10px; /* Smaller edit buttons */
font-size: 0.8em;
margin-left: 10px;
vertical-align: middle;
}
.btn.edit:hover {
background-color: #e0a800;
}
label {
display: block;
margin-bottom: 8px; /* More space */
font-weight: bold;
color: #555;
}
input[type="text"],
textarea,
select {
width: 100%; /* Use 100% width */
padding: 12px; /* More padding */
margin-bottom: 18px; /* More space */
border: 1px solid #ccc;
border-radius: 5px;
box-sizing: border-box;
font-size: 1em;
}
textarea {
resize: vertical;
min-height: 100px; /* Minimum height */
}
select {
margin-bottom: 25px;
}
.question-container {
border: 1px solid #e0e0e0;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
background-color: #f9f9f9;
}
.question-container h4 {
margin-top: 0;
margin-bottom: 15px;
color: #666;
font-size: 0.9em;
text-transform: uppercase;
}
.question-container input[type="text"] {
margin-bottom: 12px;
}
.multiple-choice-container {
margin-top: 15px;
padding-left: 15px;
border-left: 3px solid #4CAF50;
}
.multiple-choice-container label {
font-weight: normal;
margin-bottom: 8px;
}
.multiple-choice-container input[type="text"] {
width: calc(100% - 15px); /* Adjust width */
margin-left: 0; /* Remove indent */
}
/* Display Area Styling */
#createdLessons, #createdQuizzes {
margin-top: 15px;
}
#createdLessons div, #createdQuizzes div {
background-color: #fff; /* White background */
padding: 15px;
margin-bottom: 15px;
border-radius: 5px;
border: 1px solid #e0e0e0;
display: flex; /* Use flexbox for layout */
justify-content: space-between; /* Space out content and button */
align-items: center; /* Vertically align items */
}
#createdLessons div > div, #createdQuizzes div > div {
flex-grow: 1; /* Allow text content to take available space */
margin-right: 15px; /* Add space between text and button (if any) */
}
#createdLessons p, #createdQuizzes p {
margin: 0 0 5px 0; /* Adjust margins */
}
#createdLessons p strong, #createdQuizzes p strong {
font-size: 1.1em;
color: #333;
}
/* Manage Scores Modal Specific Styles */
.manage-scores-container {
padding: 10px;
}
.scores-display-area {
margin-top: 20px;
border: 1px solid #ccc;
padding: 15px;
min-height: 100px;
max-height: 400px; /* Limit height and allow scroll */
overflow-y: auto;
background-color: #f9f9f9;
}
.scores-display-area table {
width: 100%;
border-collapse: collapse;
margin-top: 10px; /* Add space above table */
}
.scores-display-area th, .scores-display-area td {
border: 1px solid #ddd;
padding: 10px 12px; /* Adjust padding */
text-align: left;
font-size: 0.95em; /* Slightly smaller font */
}
.scores-display-area th {
background-color: #e9e9e9;
font-weight: bold;
position: sticky; /* Make header sticky */
top: 0; /* Stick to the top of the scrollable area */
z-index: 1; /* Ensure header stays above table content */
}
.scores-display-area h4 { /* Style for the quiz title */
margin-bottom: 15px;
font-size: 1.2em;
color: #333;
}
.scores-display-area .no-scores-message {
font-style: italic;
color: #666;
text-align: center;
padding: 20px;
}
/* --- Analytics Button (Bottom Right, Red) --- */
.analytics-btn {
position: fixed; /* Fixed position */
bottom: 20px; /* Distance from bottom */
right: 20px; /* Distance from right */
padding: 12px 25px;
background-color: #dc3545; /* Red color */
color: white;
border: none;
border-radius: 25px; /* Pill shape */
cursor: pointer;
font-size: 15px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 999; /* Ensure it's above most content but below modals */
transition: background-color 0.3s ease, transform 0.2s ease;
}
.analytics-btn:hover {
background-color: #c82333; /* Darker red on hover */
transform: translateY(-2px); /* Slight lift on hover */
}
document.addEventListener('DOMContentLoaded', () => {
// --- Login Check ---
const loggedInUsername = sessionStorage.getItem('loggedInUsername');
const loggedInRole = sessionStorage.getItem('loggedInRole');
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'teacher') {
alert('Access denied. Please log in as a teacher.');
window.location.href = 'login.html';
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const lessonModal = document.getElementById('lessonModal');
const quizModal = document.getElementById('quizModal');
const deleteModal = document.getElementById('deleteModal');
const manageScoresModal = document.getElementById('manageScoresModal');
const analyticsModal = document.getElementById('analyticsModal');
const createLessonBtn = document.getElementById('createLessonBtn');
const createQuizBtn = document.getElementById('createQuizBtn');
const deleteLessonBtn = document.getElementById('deleteLessonBtn');
const deleteQuizBtn = document.getElementById('deleteQuizBtn'); // Re-added button
const manageScoresBtn = document.getElementById('manageScoresBtn');
const analyticsBtn = document.getElementById('analyticsBtn');
const closeButtons = document.querySelectorAll('.close');
// Lesson Form Elements
const lessonForm = document.getElementById('lessonForm');
const lessonModalTitle = document.getElementById('lessonModalTitle');
const editLessonIndexInput = document.getElementById('editLessonIndex');
const lessonTitleInput = document.getElementById('lessonTitle');
const lessonContentInput = document.getElementById('lessonContent');
const lessonSubmitBtn = document.getElementById('lessonSubmitBtn');
// Quiz Form Elements
const quizForm = document.getElementById('quizForm');
const quizModalTitle = document.getElementById('quizModalTitle');
const editQuizIndexInput = document.getElementById('editQuizIndex');
const quizTypeSelect = document.getElementById('quizType');
const quizTitleInput = document.getElementById('quizTitle');
const questionsContainer = document.getElementById('questionsContainer');
const addQuestionBtn = document.getElementById('addQuestionBtn');
const quizSubmitBtn = document.getElementById('quizSubmitBtn');
// Delete Modal Elements
const deleteTypeSelect = document.getElementById('deleteType'); // Re-added select
const deleteChoiceSelect = document.getElementById('deleteChoice');
const deleteBtn = document.getElementById('deleteBtn');
// Manage Scores Modal Elements
const quizSelectForScores = document.getElementById('quizSelectForScores');
const studentScoresDisplay = document.getElementById('studentScoresDisplay');
// Analytics Modal Elements
const lessonCountSpan = document.getElementById('lessonCount');
const quizCountSpan = document.getElementById('quizCount');
const averageQuizScoreSpan = document.getElementById('averageQuizScore');
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// Display Areas
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
let questionCount = 0;
const storageKeys = {
lessons: 'createdLessons',
quizzes: 'createdQuizzes',
studentResultPrefix: 'studentQuizResults_',
// !!! IMPORTANT: Verify this key matches your actual localStorage key for users !!!
registeredStudents: 'registeredUsers'
};
// --- Utility Functions ---
const openModal = (modal) => {
modal.style.display = "block";
if (modal.classList.contains('fullscreen')) {
document.body.classList.add('modal-open');
}
};
const closeModal = (modal) => {
modal.style.display = "none";
if (modal.classList.contains('fullscreen')) {
document.body.classList.remove('modal-open');
}
if (modal.id === 'lessonModal') resetLessonForm();
if (modal.id === 'quizModal') resetQuizForm();
if (modal.id === 'manageScoresModal') {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>'; // Use class
quizSelectForScores.value = "";
}
if (modal.id === 'deleteModal') { // Reset delete modal on close
deleteTypeSelect.value = 'lesson'; // Default back to lesson
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
}
};
const getData = (key) => {
const data = localStorage.getItem(key);
if (data && (data.startsWith('{') || data.startsWith('['))) {
try {
return JSON.parse(data);
} catch (e) {
console.error("Error parsing JSON from localStorage for key:", key, e);
// Default based on expected type
return (key === storageKeys.registeredStudents || key.startsWith(storageKeys.studentResultPrefix)) ? {} : [];
}
}
// Default based on expected type
return (key === storageKeys.registeredStudents || key.startsWith(storageKeys.studentResultPrefix)) ? {} : [];
};
const getObjectData = (key) => {
const data = localStorage.getItem(key);
if (data && data.startsWith('{')) {
try {
return JSON.parse(data);
} catch (e) {
console.error("Error parsing JSON object from localStorage for key:", key, e);
return {};
}
}
return {};
};
const setData = (key, data) => {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (e) {
console.error("Error setting data to localStorage for key:", key, e);
}
};
// --- Lesson Functions ---
const resetLessonForm = () => {
lessonForm.reset();
editLessonIndexInput.value = "-1";
lessonModalTitle.textContent = "Create Lesson";
lessonSubmitBtn.textContent = "Create Lesson";
};
const updateCreatedLessons = () => {
const lessons = getData(storageKeys.lessons);
createdLessonsDiv.innerHTML = '';
lessons.forEach((lesson, index) => {
const lessonDiv = document.createElement('div');
const contentDiv = document.createElement('div');
contentDiv.innerHTML = `<p><strong>${lesson.title}</strong></p><p>${lesson.content.substring(0, 100)}${lesson.content.length > 100 ? '...' : ''}</p>`;
lessonDiv.appendChild(contentDiv);
const editBtn = document.createElement('button');
editBtn.textContent = 'Edit';
editBtn.classList.add('btn', 'edit');
editBtn.dataset.index = index;
editBtn.addEventListener('click', () => editLesson(index));
lessonDiv.appendChild(editBtn);
createdLessonsDiv.appendChild(lessonDiv);
});
updateDeleteChoices(); // Update delete dropdown
};
const editLesson = (index) => {
const lessons = getData(storageKeys.lessons);
if (index >= 0 && index < lessons.length) {
const lesson = lessons[index];
resetLessonForm();
editLessonIndexInput.value = index;
lessonTitleInput.value = lesson.title;
lessonContentInput.value = lesson.content;
lessonModalTitle.textContent = "Edit Lesson";
lessonSubmitBtn.textContent = "Save Changes";
openModal(lessonModal);
}
};
const handleLessonFormSubmit = (event) => {
event.preventDefault();
const lessonData = {
title: lessonTitleInput.value,
content: lessonContentInput.value,
};
const editIndex = parseInt(editLessonIndexInput.value, 10);
let lessons = getData(storageKeys.lessons);
if (editIndex > -1 && editIndex < lessons.length) {
lessons[editIndex] = lessonData;
alert('Lesson Updated!');
} else {
lessons.push(lessonData);
alert('Lesson Created!');
}
setData(storageKeys.lessons, lessons);
closeModal(lessonModal);
updateCreatedLessons();
};
// --- Quiz Functions ---
const resetQuizForm = () => {
quizForm.reset();
editQuizIndexInput.value = "-1";
questionsContainer.innerHTML = '';
questionCount = 0;
quizModalTitle.textContent = "Create Quiz";
quizSubmitBtn.textContent = "Create Quiz";
quizTypeSelect.disabled = false;
toggleMultipleChoiceFields();
};
const toggleMultipleChoiceFields = () => {
const selectedType = quizTypeSelect.value;
const allQuestionContainers = questionsContainer.querySelectorAll('.question-container');
allQuestionContainers.forEach(qContainer => {
const mcContainer = qContainer.querySelector('.multiple-choice-container');
const choiceInputs = mcContainer ? mcContainer.querySelectorAll('input[type="text"]') : [];
const answerInput = qContainer.querySelector('input[name$="-correct-answer"]');
const answerLabel = answerInput ? answerInput.previousElementSibling : null;
if (mcContainer) {
mcContainer.style.display = selectedType === 'multiple-choice' ? 'block' : 'none';
choiceInputs.forEach(input => input.required = (selectedType === 'multiple-choice'));
}
if (answerLabel && answerLabel.tagName === 'LABEL') {
answerLabel.textContent = selectedType === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):';
}
});
};
const addQuestion = (questionData = null) => {
const currentQIndex = questionData ? questionData.qIndex : ++questionCount;
const questionDiv = document.createElement('div');
questionDiv.classList.add('question-container');
questionDiv.dataset.qIndex = currentQIndex;
const qText = questionData ? questionData.questionText : '';
const qAnswer = questionData ? questionData.correctAnswer : '';
const qChoices = questionData ? questionData.choices : ['', '', '', ''];
questionDiv.innerHTML = `
<h4>Question ${currentQIndex}</h4>
<label for="question-${currentQIndex}">Question Text:</label>
<input type="text" id="question-${currentQIndex}" name="question-${currentQIndex}" value="${qText}" required><br>
<div class="multiple-choice-container">
<label>Choices:</label><br>
<input type="text" name="question-${currentQIndex}-choice-1" placeholder="Choice 1" value="${qChoices[0] || ''}" required><br>
<input type="text" name="question-${currentQIndex}-choice-2" placeholder="Choice 2" value="${qChoices[1] || ''}" required><br>
<input type="text" name="question-${currentQIndex}-choice-3" placeholder="Choice 3" value="${qChoices[2] || ''}" required><br>
<input type="text" name="question-${currentQIndex}-choice-4" placeholder="Choice 4" value="${qChoices[3] || ''}" required><br>
</div>
<label for="question-${currentQIndex}-correct-answer">Correct Answer:</label>
<input type="text" name="question-${currentQIndex}-correct-answer" value="${qAnswer}" required><br>
`;
questionsContainer.appendChild(questionDiv);
if (!questionData) questionCount = currentQIndex;
toggleMultipleChoiceFields();
};
const updateCreatedQuizzes = () => {
const quizzes = getData(storageKeys.quizzes);
createdQuizzesDiv.innerHTML = '';
quizzes.forEach((quiz, index) => {
const quizDiv = document.createElement('div');
const contentDiv = document.createElement('div');
contentDiv.innerHTML = `<p><strong>${quiz.quizTitle}</strong></p><p>(Type: ${quiz.quizType}, Questions: ${quiz.questions.length})</p>`;
quizDiv.appendChild(contentDiv);
// No Edit button for quizzes
createdQuizzesDiv.appendChild(quizDiv);
});
updateDeleteChoices(); // Update delete dropdown
populateQuizSelectForScores();
};
// Edit Quiz function remains but is not called from UI
const editQuiz = (index) => {
const quizzes = getData(storageKeys.quizzes);
if (index >= 0 && index < quizzes.length) {
const quiz = quizzes[index];
resetQuizForm();
editQuizIndexInput.value = index;
quizTitleInput.value = quiz.quizTitle;
quizTypeSelect.value = quiz.quizType;
quizTypeSelect.disabled = true;
questionCount = 0;
quiz.questions.forEach((q, qIndex) => {
addQuestion({ ...q, qIndex: qIndex + 1 });
});
quizModalTitle.textContent = "Edit Quiz";
quizSubmitBtn.textContent = "Save Changes";
openModal(quizModal);
toggleMultipleChoiceFields();
}
};
const handleQuizFormSubmit = (event) => {
event.preventDefault();
const editIndex = parseInt(editQuizIndexInput.value, 10);
const quizType = quizTypeSelect.value;
const quizTitle = quizTitleInput.value;
const questions = [];
const questionElements = questionsContainer.querySelectorAll('.question-container');
const currentQuestionCount = questionElements.length;
for (let i = 1; i <= currentQuestionCount; i++) {
const qContainer = questionsContainer.querySelector(`.question-container[data-q-index="${i}"]`);
if (!qContainer) continue;
const questionText = qContainer.querySelector(`[name='question-${i}']`)?.value;
const correctAnswer = qContainer.querySelector(`[name='question-${i}-correct-answer']`)?.value;
const choices = [];
if (!questionText || correctAnswer === undefined || correctAnswer === null || correctAnswer === "") {
alert(`Please fill out question text and correct answer for Question ${i}.`);
return;
}
if (quizType === 'multiple-choice') {
const choiceInputs = qContainer.querySelectorAll(`[name='question-${i}-choice-1'], [name='question-${i}-choice-2'], [name='question-${i}-choice-3'], [name='question-${i}-choice-4']`);
let choicesComplete = true;
choiceInputs.forEach(input => {
if (!input.value) choicesComplete = false;
choices.push(input.value);
});
if (!choicesComplete) {
alert(`Please fill out all choices for Question ${i}.`);
return;
}
if (!choices.includes(correctAnswer)) {
alert(`The correct answer for Question ${i} must match one of the provided choices.`);
return;
}
}
questions.push({ questionText, choices: quizType === 'multiple-choice' ? choices : [], correctAnswer });
}
if (questions.length === 0) {
alert('Please add at least one question to the quiz.');
return;
}
const quizData = { quizType, quizTitle, questions };
let quizzes = getData(storageKeys.quizzes);
if (editIndex > -1 && editIndex < quizzes.length) {
quizzes[editIndex] = quizData;
alert('Quiz Updated!');
} else {
quizzes.push(quizData);
alert('Quiz Created!');
}
setData(storageKeys.quizzes, quizzes);
closeModal(quizModal);
updateCreatedQuizzes();
};
// --- Delete Functions (Handles both Lessons and Quizzes) ---
const updateDeleteChoices = () => {
const deleteType = deleteTypeSelect.value; // Read the selected type
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
const items = getData(deleteType === "lesson" ? storageKeys.lessons : storageKeys.quizzes);
items.forEach((item, index) => {
const option = document.createElement('option');
option.value = index;
// Use 'title' for lessons and 'quizTitle' for quizzes
option.textContent = item.title || item.quizTitle || `${deleteType} ${index + 1}`;
deleteChoiceSelect.appendChild(option);
});
deleteBtn.disabled = items.length === 0;
};
const handleDelete = () => {
const selectedIndex = deleteChoiceSelect.value;
const deleteType = deleteTypeSelect.value; // Get the type from the dropdown
if (selectedIndex === "") {
alert('Please select an item to delete.');
return;
}
const storageKey = deleteType === 'lesson' ? storageKeys.lessons : storageKeys.quizzes;
let items = getData(storageKey);
const itemName = items[selectedIndex]?.title || items[selectedIndex]?.quizTitle || `${deleteType} ${parseInt(selectedIndex)+1}`;
if (confirm(`Are you sure you want to delete ${deleteType} "${itemName}"? This cannot be undone.`)) {
items.splice(selectedIndex, 1);
setData(storageKey, items);
alert(`${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} Deleted!`);
// Update the correct display
if (deleteType === 'lesson') {
updateCreatedLessons();
} else {
updateCreatedQuizzes();
}
closeModal(deleteModal); // Close and reset the modal
}
};
// --- Manage Scores Functions ---
const populateQuizSelectForScores = () => {
const quizzes = getData(storageKeys.quizzes);
quizSelectForScores.innerHTML = '<option value="">-- Select a Quiz --</option>';
quizzes.forEach((quiz, index) => {
const option = document.createElement('option');
option.value = index;
option.textContent = quiz.quizTitle;
quizSelectForScores.appendChild(option);
});
};
const displayStudentScores = () => {
const selectedQuizIndex = quizSelectForScores.value;
studentScoresDisplay.innerHTML = ''; // Clear previous content
console.log(`Displaying scores for quiz index: ${selectedQuizIndex}`); // Log: Start
if (selectedQuizIndex === "") {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
return;
}
const quizzes = getData(storageKeys.quizzes);
const selectedQuiz = quizzes[selectedQuizIndex];
if (!selectedQuiz) {
console.error(`Error: Could not find quiz data for index ${selectedQuizIndex}`);
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Error: Could not find selected quiz.</p>';
return;
}
console.log("Selected Quiz Data:", selectedQuiz); // Log: Quiz data
// --- Get student results ---
const registeredUsers = getObjectData(storageKeys.registeredStudents);
console.log("Registered Users Data:", registeredUsers); // Log: All registered users
// Filter for students
const studentUsernames = Object.keys(registeredUsers).filter(username => registeredUsers[username]?.role === 'student');
console.log("Filtered Student Usernames:", studentUsernames); // Log: Student usernames
if (!studentUsernames || studentUsernames.length === 0) {
console.log("No registered users with role 'student' found."); // Log: No students
studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered students found.</p>';
return;
}
let tableHTML = `
<h4>Scores for: ${selectedQuiz.quizTitle}</h4>
<table>
<thead>
<tr>
<th>Student</th>
<th>Score</th>
<th>Percentage</th>
<th>Date Taken</th>
</tr>
</thead>
<tbody>
`;
let scoresFound = false;
studentUsernames.forEach(username => {
const studentResultKey = `${storageKeys.studentResultPrefix}${username}`;
console.log(`Checking results for student: ${username} (key: ${studentResultKey})`); // Log: Checking student
const studentResults = getObjectData(studentResultKey); // Fetch results for this student
console.log(`Results object for ${username}:`, studentResults); // Log: Student's full results object
// Check if this student has a result for the selected quiz index
// Use bracket notation for the index as it's a variable
const result = studentResults[selectedQuizIndex];
console.log(`Result for quiz index ${selectedQuizIndex}:`, result); // Log: Specific quiz result
if (result) { // Check if result exists for this index
scoresFound = true;
const score = typeof result.score === 'number' ? result.score : 'N/A';
const total = typeof result.total === 'number' ? result.total : 'N/A';
let percentage = 'N/A';
if (typeof score === 'number' && typeof total === 'number' && total > 0) {
percentage = ((score / total) * 100).toFixed(1) + '%';
} else if (typeof score === 'number' && typeof total === 'number' && total === 0) {
percentage = 'N/A (0 questions)';
}
const dateTaken = result.timestamp ? new Date(result.timestamp).toLocaleString() : 'N/A';
tableHTML += `
<tr>
<td>${username}</td>
<td>${score} / ${total}</td>
<td>${percentage}</td>
<td>${dateTaken}</td>
</tr>
`;
} else {
console.log(`No result found for quiz index ${selectedQuizIndex} for student ${username}`); // Log: No result found
}
});
if (!scoresFound) {
console.log("No scores found for any student for this quiz."); // Log: No scores found overall
tableHTML += '<tr><td colspan="4" class="no-scores-message">No students have taken this quiz yet.</td></tr>';
}
tableHTML += '</tbody></table>';
studentScoresDisplay.innerHTML = tableHTML;
};
// --- Analytics Modal Functions ---
const openAnalyticsModal = () => {
populateTeacherAnalytics();
openModal(analyticsModal);
};
const closeAnalyticsModal = () => {
closeModal(analyticsModal);
};
const populateTeacherAnalytics = () => {
const lessons = getData(storageKeys.lessons);
const quizzes = getData(storageKeys.quizzes);
lessonCountSpan.textContent = lessons.length;
quizCountSpan.textContent = quizzes.length;
let totalPercentageSum = 0;
let totalQuizzesTakenCount = 0;
const registeredUsers = getObjectData(storageKeys.registeredStudents);
const studentUsernames = Object.keys(registeredUsers).filter(username => registeredUsers[username]?.role === 'student');
studentUsernames.forEach(username => {
const studentResultKey = `${storageKeys.studentResultPrefix}${username}`;
const studentResults = getObjectData(studentResultKey);
Object.values(studentResults).forEach(result => {
if (result && typeof result.score === 'number' && typeof result.total === 'number' && result.total > 0) {
totalPercentageSum += (result.score / result.total) * 100;
totalQuizzesTakenCount++;
}
});
});
if (totalQuizzesTakenCount > 0) {
averageQuizScoreSpan.textContent = (totalPercentageSum / totalQuizzesTakenCount).toFixed(1) + '%';
} else {
averageQuizScoreSpan.textContent = 'N/A';
}
};
// --- Navigation Logic ---
function goToHomepage() {
window.location.href = 'homepage.html';
}
function logout() {
sessionStorage.removeItem('loggedInUsername');
sessionStorage.removeItem('loggedInRole');
alert('You have been logged out.');
window.location.href = 'login.html';
}
// --- Event Listeners ---
// Standard Modals Open/Close
createLessonBtn.addEventListener('click', () => { resetLessonForm(); openModal(lessonModal); });
createQuizBtn.addEventListener('click', () => { resetQuizForm(); addQuestion(); openModal(quizModal); });
// Delete Lesson Button opens delete modal with type 'lesson' selected
deleteLessonBtn.addEventListener('click', () => {
deleteTypeSelect.value = "lesson"; // Set type
updateDeleteChoices(); // Populate choices for lessons
openModal(deleteModal);
});
// Delete Quiz Button opens delete modal with type 'quiz' selected
deleteQuizBtn.addEventListener('click', () => {
deleteTypeSelect.value = "quiz"; // Set type
updateDeleteChoices(); // Populate choices for quizzes
openModal(deleteModal);
});
manageScoresBtn.addEventListener('click', () => { populateQuizSelectForScores(); studentScoresDisplay.innerHTML='<p class="no-scores-message">Select a quiz to view student scores.</p>'; openModal(manageScoresModal); });
closeButtons.forEach(button => {
button.addEventListener('click', () => {
const modalId = button.getAttribute('data-modal-id');
if (modalId) {
const modalToClose = document.getElementById(modalId);
if (modalToClose) closeModal(modalToClose);
}
});
});
window.addEventListener('click', (event) => {
if (event.target.classList.contains('modal') && !event.target.classList.contains('fullscreen')) {
closeModal(event.target);
}
});
// Form Submissions
lessonForm.addEventListener('submit', handleLessonFormSubmit);
quizForm.addEventListener('submit', handleQuizFormSubmit);
// Quiz Form - Add Question & Type Change
addQuestionBtn.addEventListener('click', () => addQuestion());
quizTypeSelect.addEventListener('change', toggleMultipleChoiceFields);
// Delete Modal - Type Change & Delete Button
deleteTypeSelect.addEventListener('change', updateDeleteChoices); // Update choices when type changes
deleteBtn.addEventListener('click', handleDelete);
// Manage Scores Modal - Quiz Selection Change
quizSelectForScores.addEventListener('change', displayStudentScores);
// Analytics Modal Open/Close/Navigation
analyticsBtn.addEventListener('click', openAnalyticsModal);
modalDashboardBtn.addEventListener('click', closeAnalyticsModal);
modalHomeBtn.addEventListener('click', goToHomepage);
modalLogoutBtn.addEventListener('click', logout);
// --- Initial Load ---
updateCreatedLessons();
updateCreatedQuizzes();
});
this is the student dashboard code and make it compatible and make sure the username of the student will appear after they submit the quiz:
<!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 --- */
.correct-mark {
color: green;
font-weight: bold;
margin-left: 8px;
font-size: 1.2em;
}
.incorrect-mark {
color: red;
font-weight: bold;
margin-left: 8px;
font-size: 1.2em;
}
.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';
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
studentQuizResults: `studentQuizResults_${loggedInUsername}`, // User-specific results
lastAccessed: `studentLastAccessed_${loggedInUsername}` // User-specific last access
};
// --- Utility Functions ---
const getData = (key) => {
const data = localStorage.getItem(key);
if (data && (data.startsWith('{') || data.startsWith('['))) {
try {
return JSON.parse(data);
} catch (e) {
console.error("Error parsing JSON from localStorage for key:", key, e);
return (key.startsWith('studentQuizResults')) ? {} : [];
}
}
if (key.startsWith('studentLastAccessed')) return data;
return (key.startsWith('studentQuizResults')) ? {} : [];
};
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');
lessonDiv.innerHTML = `<h4>${lesson.title}</h4><p>${lesson.content}</p>`;
createdLessonsDiv.appendChild(lessonDiv);
});
}
// --- Quiz Display and Taking Logic ---
function updateCreatedQuizzes() {
console.log("Updating created quizzes display..."); // Debug log
const quizzes = getData(storageKeys.quizzes);
const results = getData(storageKeys.studentQuizResults);
createdQuizzesDiv.innerHTML = ''; // Clear previous content
if (quizzes.length === 0) {
createdQuizzesDiv.innerHTML = '<p>No quizzes available.</p>';
checkAndEnforceQuizCompletion();
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}`;
const hasTaken = results[index] !== undefined;
console.log(`Quiz Index: ${index}, Title: ${quiz.quizTitle}, Has Taken: ${hasTaken}`); // Debug log
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 ? `<h3>Your Score: ${results[index].score} / ${results[index].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;
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
document.querySelectorAll('.quiz-questions-area').forEach(area => area.style.display = 'none');
document.querySelectorAll('.take-quiz-btn').forEach(btn => btn.style.display = 'inline-block'); // Show other take buttons
questionsArea.innerHTML = ''; // Clear previous content
scoreArea.innerHTML = '';
scoreArea.style.display = 'none';
questionsArea.style.display = 'block';
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}`);
}
choices.forEach((choice, cIndex) => {
const choiceText = choice || `Choice ${cIndex + 1}`;
// Ensure value is unique and consistent, handle null/undefined choices
const choiceValue = (choice !== null && choice !== undefined) ? choice : `__choice_${cIndex}__`; // Use a prefix to avoid potential clashes with actual answers like "choice_1"
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}`);
// Optionally provide a default message or skip
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 if questions were added
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
questionsArea.appendChild(submitButton);
} else if (questionsArea.children.length === 0) {
questionsArea.innerHTML = '<p><em>No valid questions found for this quiz.</em></p>';
}
}
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');
const scoreArea = document.getElementById(`score-area-${quizIndex}`);
if (!questionsArea || !scoreArea) {
console.error("Could not find questions or score area for quiz index:", quizIndex);
return;
}
let score = 0;
let allAnswered = true;
// Clear previous feedback
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'));
quiz.questions.forEach((question, qIndex) => {
// Skip if question was invalid during startQuiz
if (!question || typeof question.questionText === 'undefined') {
return;
}
let studentAnswer = null;
const correctAnswer = question.correctAnswer;
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 for qIndex ${qIndex} during submission in quiz ${quizIndex}`);
allAnswered = false; // Consider it unanswered if the element is missing
return;
}
if (quiz.quizType === 'identification') {
const inputElement = questionElement.querySelector(`input[type="text"]`);
studentAnswer = inputElement ? inputElement.value.trim() : null;
if (inputElement) inputElement.disabled = true;
if (studentAnswer === null || studentAnswer === "") {
allAnswered = false;
} else if (correctAnswer !== undefined && correctAnswer !== null && studentAnswer.toLowerCase() === String(correctAnswer).toLowerCase()) {
score++;
isCorrect = true;
} else if (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;
radioButtons.forEach(radio => radio.disabled = true);
if (!studentAnswer) {
allAnswered = false;
} else {
// Determine the value corresponding to the correct answer text/object
let correctValue = correctAnswer; // Assume correct answer is stored directly as the value
const choices = Array.isArray(question.choices) ? question.choices : [];
const correctChoiceIndex = choices.findIndex(c => c === correctAnswer);
// If correct answer is null/undefined, check if its value should be the special `__choice_${index}__`
if (correctAnswer === null || correctAnswer === undefined) {
if (correctChoiceIndex !== -1) {
correctValue = `__choice_${correctChoiceIndex}__`;
}
}
// If studentAnswer is the special value, compare against the derived correctValue
if (studentAnswer === correctValue) {
score++;
isCorrect = true;
}
}
radioButtons.forEach(radio => {
const choiceLabel = radio.closest('label');
if (!choiceLabel) return;
let correctValue = correctAnswer;
const choices = Array.isArray(question.choices) ? question.choices : [];
const correctChoiceIndex = choices.findIndex(c => c === correctAnswer);
if (correctAnswer === null || correctAnswer === undefined) {
if (correctChoiceIndex !== -1) {
correctValue = `__choice_${correctChoiceIndex}__`;
}
}
if (radio.value === correctValue) {
choiceLabel.classList.add('correct-answer-highlight');
}
if (radio.checked && !isCorrect) {
choiceLabel.classList.add('incorrect-choice-selected');
}
});
}
if (questionNumberElement && studentAnswer !== null && studentAnswer !== "") {
const feedbackMark = document.createElement('span');
feedbackMark.classList.add('feedback-mark');
feedbackMark.textContent = isCorrect ? '✓' : '✗';
feedbackMark.classList.add(isCorrect ? 'correct-mark' : 'incorrect-mark');
questionNumberElement.appendChild(feedbackMark);
}
});
if (!allAnswered) {
alert('Please answer all questions before submitting.');
const inputsAndRadios = questionsArea.querySelectorAll('input[type="text"], input[type="radio"]');
inputsAndRadios.forEach(input => input.disabled = false); // Re-enable for correction
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'));
return; // Stop submission
}
// --- If validation passes ---
scoreArea.innerHTML = `<h3>Your Score: ${score} / ${quiz.questions.length}</h3>`;
scoreArea.style.display = 'block';
buttonElement.disabled = true; // Disable the submit button
buttonElement.textContent = 'Submitted';
// Find the original "Take Quiz" button again and disable it
const originalTakeButton = document.querySelector(`.take-quiz-btn[data-quiz-index="${quizIndex}"]`);
if (originalTakeButton) {
originalTakeButton.disabled = true;
originalTakeButton.textContent = 'Quiz Taken';
}
saveQuizResult(quizIndex, quiz.quizTitle, score, quiz.questions.length);
checkAndEnforceQuizCompletion();
}
function saveQuizResult(quizIndex, quizTitle, score, totalQuestions) {
const results = getData(storageKeys.studentQuizResults);
results[quizIndex] = {
title: quizTitle || 'Untitled Quiz', // Use fallback title
score: score,
total: totalQuestions,
timestamp: new Date().toISOString()
};
setData(storageKeys.studentQuizResults, results);
console.log("Quiz result saved for index:", quizIndex, results[quizIndex]);
}
// --- Quiz Completion Enforcement ---
function checkAndEnforceQuizCompletion() {
const quizzes = getData(storageKeys.quizzes);
const results = getData(storageKeys.studentQuizResults);
let allQuizzesTaken = true;
// Ensure quizzes is an array before checking length
const numQuizzes = Array.isArray(quizzes) ? quizzes.length : 0;
if (numQuizzes === 0) {
allQuizzesTaken = true; // No quizzes to take
} else {
for (let i = 0; i < numQuizzes; i++) {
// Also check if the quiz itself is valid before checking results
if (!quizzes[i] || typeof quizzes[i].quizTitle === 'undefined' || !Array.isArray(quizzes[i].questions)) {
continue; // Skip invalid quiz entries in the completion check
}
if (results[i] === undefined) {
allQuizzesTaken = false;
break; // Found an untaken, valid quiz
}
}
}
console.log("All valid quizzes taken:", allQuizzesTaken);
if (allQuizzesTaken) {
quizCompletionStatusDiv.classList.add('hidden');
analyticsBtn.disabled = false;
console.log("Analytics button enabled.");
} else {
quizCompletionStatusDiv.classList.remove('hidden');
analyticsBtn.disabled = true;
console.log("Analytics button disabled.");
}
}
// --- 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');
}
function closeAnalyticsModal() {
analyticsModal.style.display = 'none';
document.body.classList.remove('modal-open');
}
function populateAnalyticsData() {
const lastAccessedISO = localStorage.getItem(storageKeys.lastAccessed);
lastAccessedSpan.textContent = lastAccessedISO ? new Date(lastAccessedISO).toLocaleString() : 'Not recorded yet.';
const results = getData(storageKeys.studentQuizResults);
const quizIndices = Object.keys(results); // Indices of TAKEN quizzes
quizScoresListUl.innerHTML = '';
const quizzes = getData(storageKeys.quizzes); // All available quizzes
if (quizIndices.length === 0) {
quizScoresListUl.innerHTML = '<li>No quizzes taken yet.</li>';
overallGradeSpan.textContent = 'N/A';
return;
}
let totalScore = 0;
let totalPossibleScore = 0;
quizIndices.sort((a, b) => parseInt(a) - parseInt(b)); // Sort taken quiz indices
quizIndices.forEach(index => {
const result = results[index];
// Ensure result has expected properties before calculating
if (typeof result.score !== 'number' || typeof result.total !== 'number') {
console.warn(`Invalid result data for index ${index}:`, result);
return; // Skip invalid result
}
// 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;
});
// 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';
}
function logout() {
sessionStorage.removeItem('loggedInUsername');
sessionStorage.removeItem('loggedInRole');
alert('You have been logged out.');
window.location.href = 'login.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();
updateCreatedLessons();
updateCreatedQuizzes(); // Initial population and check
});