Add a due date button when the teacher creates quiz and assignment, when can it be completed? And if the quiz and assignment has passed the date and time, students will no longer be able to complete it on the student dashboard. You don't have to remove anything from the code, just add a due date for the quiz and assignment. I also need the full code for this.
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;
}
// Add notification icon to navbar
const navbar = document.createElement('div');
navbar.className = 'teacher-navbar';
navbar.innerHTML = `
<h1>Teacher Dashboard</h1>
`;
document.body.insertBefore(navbar, document.body.firstChild);
// Notification system
const notifyStudents = (type, details) => {
// Parse userData from localStorage
const userData = JSON.parse(localStorage.getItem('userData') || '{}');
// Ensure userData is an object
if (typeof userData !== 'object' || userData === null) {
console.error('Invalid userData in localStorage');
return;
}
// Filter students from userData
const students = Object.values(userData).filter(user => user.role === 'student');
// Notify each student
students.forEach(student => {
let message = '';
// Generate appropriate message based on notification type
switch (type) {
case 'lesson':
message = `New lesson available: ${details.title}`;
break;
case 'quiz':
message = `New quiz available: ${details.quizTitle} - Due: ${details.dueDate}`;
break;
case 'assignment':
message = `New assignment: ${details.title} - Due: ${details.dueDate}`;
break;
default:
console.error(`Unknown notification type: ${type}`);
return; // Exit if type is not recognized
}
// Initialize notifications if not present
if (!student.notifications) {
student.notifications = [];
}
// Push the new notification
student.notifications.push({
type,
message,
timestamp: new Date().toISOString(),
read: false,
});
});
// Update userData in localStorage
localStorage.setItem('userData', JSON.stringify(userData));
// Update notification count in the navbar
updateNotificationCount();
};
// Update notification count in navbar
const updateNotificationCount = () => {
// Parse userData from localStorage
const userData = JSON.parse(localStorage.getItem('userData') || '{}');
// Define a placeholder for the logged-in username (replace this with actual logic)
const loggedInUsername = localStorage.getItem('loggedInUsername'); // Example retrieval
if (!loggedInUsername || !userData[loggedInUsername]) {
console.error('Logged-in user data is not found');
return;
}
// Get unread notifications count
const teacher = userData[loggedInUsername];
const unreadCount = teacher.notifications?.filter(n => !n.read).length || 0;
// Update the notification count in the DOM
const notificationCountElement = document.querySelector('.notification-count');
if (notificationCountElement) {
notificationCountElement.textContent = unreadCount;
} else {
console.error('.notification-count element not found in the DOM');
}
};
// Initialize notification count
updateNotificationCount();
// --- 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 assignmentModal = document.getElementById('assignmentModal');
const respondentsModal = document.getElementById('respondentsModal');
const respondentsList = document.getElementById('respondentsList');
const createLessonBtn = document.getElementById('createLessonBtn');
const createQuizBtn = document.getElementById('createQuizBtn');
const deleteLessonBtn = document.getElementById('deleteLessonBtn');
const deleteQuizBtn = document.getElementById('deleteQuizBtn');
const manageScoresBtn = document.getElementById('manageScoresBtn');
const analyticsBtn = document.getElementById('analyticsBtn');
const createAssignmentBtn = document.getElementById('createAssignmentBtn');
const deleteAssignmentBtn = document.getElementById('deleteAssignmentBtn');
const closeRespondentsModal = document.getElementById('closeRespondentsModal');
const deleteTypeSelect = document.getElementById('deleteType');
const deleteChoiceSelect = document.getElementById('deleteChoice');
const deleteBtn = document.getElementById('deleteBtn');
const createdAssignmentsDiv = document.getElementById('createdAssignments');
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 lessonFileInput = document.getElementById('lessonFile');
const currentFileNameSpan = document.getElementById('currentFileName').querySelector('span');
const currentFileNameDisplay = document.getElementById('currentFileName');
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 quizDueDateInput = document.getElementById('quizDueDate');
const questionsContainer = document.getElementById('questionsContainer');
const addQuestionBtn = document.getElementById('addQuestionBtn');
const quizSubmitBtn = document.getElementById('quizSubmitBtn');
// 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');
// Assignment Form Elements
const assignmentForm = document.getElementById('assignmentForm');
const assignmentModalTitle = document.getElementById('assignmentModalTitle');
const editAssignmentIndexInput = document.getElementById('editAssignmentIndex');
const assignmentTitleInput = document.getElementById('assignmentTitle');
const assignmentDescriptionInput = document.getElementById('assignmentDescription');
const assignmentDueDateInput = document.getElementById('assignmentDueDate');
const assignmentFileInput = document.getElementById('assignmentFile');
const currentAssignmentFileNameSpan = document.getElementById('currentAssignmentFileName').querySelector('span');
const currentAssignmentFileNameDisplay = document.getElementById('currentAssignmentFileName');
const assignmentSubmitBtn = document.getElementById('assignmentSubmitBtn');
// Display Areas
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
let questionCount = 0;
const storageKeys = {
lessons: 'createdLessons',
quizzes: 'createdQuizzes',
assignments: 'createdAssignments',
users: '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 === 'assignmentModal') resetAssignmentForm();
if (modal.id === 'manageScoresModal') {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
quizSelectForScores.value = "";
}
if (modal.id === 'deleteModal') {
deleteTypeSelect.value = 'lesson';
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
}
};
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 [];
};
if (typeof getUsers !== 'function') {
console.error("Error: getUsers function not found. Make sure login.js is included before teacher.js");
alert("A critical error occurred. Please try refreshing the page or logging in again.");
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);
if (e.name === 'QuotaExceededError') {
alert('Error: Could not save data. Local storage quota exceeded. This might be due to a large file upload.');
} else {
alert('An error occurred while saving data.');
}
}
};
// --- Assignment Functions ---
const resetAssignmentForm = () => {
assignmentForm.reset();
editAssignmentIndexInput.value = "-1";
assignmentModalTitle.textContent = "Create Assignment";
assignmentSubmitBtn.textContent = "Create Assignment";
currentAssignmentFileNameDisplay.style.display = 'none';
currentAssignmentFileNameSpan.textContent = '';
};
const editAssignment = (index) => {
const assignments = getData(storageKeys.assignments);
if (index >= 0 && index < assignments.length) {
const assignment = assignments[index];
resetAssignmentForm();
editAssignmentIndexInput.value = index;
assignmentTitleInput.value = assignment.title;
assignmentDescriptionInput.value = assignment.description;
assignmentDueDateInput.value = assignment.dueDate;
if (assignment.fileName) {
currentAssignmentFileNameSpan.textContent = assignment.fileName;
currentAssignmentFileNameDisplay.style.display = 'block';
} else {
currentAssignmentFileNameDisplay.style.display = 'none';
}
assignmentModalTitle.textContent = "Edit Assignment";
assignmentSubmitBtn.textContent = "Save Changes";
openModal(assignmentModal);
}
};
const updateCreatedAssignments = () => {
const assignments = getData(storageKeys.assignments);
createdAssignmentsDiv.innerHTML = '';
assignments.forEach((assignment, index) => {
const assignmentDiv = document.createElement('div');
const contentDiv = document.createElement('div');
let fileInfo = '';
if (assignment.fileName) {
fileInfo = `<p><small><em>Attachment: ${assignment.fileName}</em></small></p>`;
}
contentDiv.innerHTML = `
<p><strong>${assignment.title}</strong></p>
<p>${assignment.description.substring(0, 100)}${assignment.description.length > 100 ? '...' : ''}</p>
<p><small>Due: ${assignment.dueDate}</small></p>
${fileInfo}
`;
assignmentDiv.appendChild(contentDiv);
const editBtn = document.createElement('button');
editBtn.textContent = 'Edit';
editBtn.classList.add('btn', 'edit');
editBtn.dataset.index = index;
editBtn.addEventListener('click', () => editAssignment(index));
assignmentDiv.appendChild(editBtn);
const respondentsBtn = document.createElement('button');
respondentsBtn.textContent = 'View Respondents';
respondentsBtn.classList.add('btn', 'respondents');
respondentsBtn.dataset.index = index;
respondentsBtn.addEventListener('click', () => showAssignmentRespondents(index));
assignmentDiv.appendChild(respondentsBtn);
createdAssignmentsDiv.appendChild(assignmentDiv);
});
};
const handleAssignmentFormSubmit = (event) => {
event.preventDefault();
const file = assignmentFileInput.files[0];
const editIndex = parseInt(editAssignmentIndexInput.value, 10);
let assignments = getData(storageKeys.assignments);
let existingAssignmentData = (editIndex > -1 && editIndex < assignments.length) ? assignments[editIndex] : {};
const assignmentData = {
title: assignmentTitleInput.value,
description: assignmentDescriptionInput.value,
dueDate: assignmentDueDateInput.value,
fileName: existingAssignmentData.fileName || null,
fileDataUrl: existingAssignmentData.fileDataUrl || null,
createdAt: new Date().toISOString()
};
const saveData = () => {
if (editIndex > -1 && editIndex < assignments.length) {
assignments[editIndex] = assignmentData;
alert('Assignment Updated!');
} else {
assignments.push(assignmentData);
alert('Assignment Created!');
}
setData(storageKeys.assignments, assignments);
closeModal(assignmentModal);
updateCreatedAssignments();
notifyStudents('assignment', assignmentData);
};
if (file) {
const maxSizeMB = 2;
if (file.size > maxSizeMB * 1024 * 1024) {
alert(`File is too large. Maximum size is ${maxSizeMB}MB.`);
assignmentFileInput.value = '';
return;
}
const reader = new FileReader();
reader.onloadend = function() {
assignmentData.fileName = file.name;
assignmentData.fileDataUrl = reader.result;
saveData();
}
reader.onerror = function() {
alert('Error reading file.');
console.error("File reading error:", reader.error);
}
reader.readAsDataURL(file);
} else {
if (editIndex > -1 && !existingAssignmentData.fileName) {
assignmentData.fileName = null;
assignmentData.fileDataUrl = null;
}
saveData();
}
};
const showAssignmentRespondents = (assignmentIndex) => {
const assignments = getData(storageKeys.assignments);
if (assignmentIndex < 0 || assignmentIndex >= assignments.length) {
alert('Invalid assignment selection');
return;
}
const assignment = assignments[assignmentIndex];
const users = getUsers();
const studentUsernames = Object.keys(users).filter(u => users[u].role === 'student');
let respondentsHTML = '';
let hasRespondents = false;
studentUsernames.forEach(username => {
const student = users[username];
if (student.assignmentStatus) {
const submission = student.assignmentStatus.find(
status => status.assignmentName === assignment.title && status.status === 'completed'
);
if (submission) {
hasRespondents = true;
respondentsHTML += `
<div class="respondent">
<p><strong>${username}</strong></p>
<p>Submitted: ${new Date(submission.timestamp).toLocaleString()}</p>
${submission.fileName ? `<p>File: ${submission.fileName}</p>` : ''}
</div>
<hr>
`;
}
}
});
if (!hasRespondents) {
respondentsHTML = '<p>No students have submitted this assignment yet.</p>';
}
respondentsList.innerHTML = `
<h3>${assignment.title}</h3>
<p>Due: ${assignment.dueDate}</p>
<div class="respondents-container">
${respondentsHTML}
</div>
`;
openModal(respondentsModal);
};
// --- Lesson Functions ---
const resetLessonForm = () => {
lessonForm.reset();
editLessonIndexInput.value = "-1";
lessonModalTitle.textContent = "Create Lesson";
lessonSubmitBtn.textContent = "Create Lesson";
currentFileNameDisplay.style.display = 'none';
currentFileNameSpan.textContent = '';
};
const updateCreatedLessons = () => {
const lessons = getData(storageKeys.lessons);
createdLessonsDiv.innerHTML = '';
lessons.forEach((lesson, index) => {
const lessonDiv = document.createElement('div');
const contentDiv = document.createElement('div');
let fileInfo = '';
if (lesson.fileName) {
fileInfo = `<p><small><em>Attachment: ${lesson.fileName}</em></small></p>`;
}
contentDiv.innerHTML = `<p><strong>${lesson.title}</strong></p><p>${lesson.content.substring(0, 100)}${lesson.content.length > 100 ? '...' : ''}</p>${fileInfo}`;
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();
};
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;
if (lesson.fileName) {
currentFileNameSpan.textContent = lesson.fileName;
currentFileNameDisplay.style.display = 'block';
} else {
currentFileNameDisplay.style.display = 'none';
}
lessonModalTitle.textContent = "Edit Lesson";
lessonSubmitBtn.textContent = "Save Changes";
openModal(lessonModal);
}
};
const handleLessonFormSubmit = (event) => {
event.preventDefault();
const file = lessonFileInput.files[0];
const editIndex = parseInt(editLessonIndexInput.value, 10);
let lessons = getData(storageKeys.lessons);
let existingLessonData = (editIndex > -1 && editIndex < lessons.length) ? lessons[editIndex] : {};
const lessonData = {
title: lessonTitleInput.value,
content: lessonContentInput.value,
fileName: existingLessonData.fileName || null,
fileDataUrl: existingLessonData.fileDataUrl || null,
createdAt: new Date().toISOString()
};
const saveData = () => {
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();
notifyStudents('lesson', lessonData);
};
if (file) {
const maxSizeMB = 2;
if (file.size > maxSizeMB * 1024 * 1024) {
alert(`File is too large. Maximum size is ${maxSizeMB}MB.`);
lessonFileInput.value = '';
return;
}
const reader = new FileReader();
reader.onloadend = function() {
lessonData.fileName = file.name;
lessonData.fileDataUrl = reader.result;
saveData();
}
reader.onerror = function() {
alert('Error reading file.');
console.error("File reading error:", reader.error);
}
reader.readAsDataURL(file);
} else {
if (editIndex > -1 && !existingLessonData.fileName) {
lessonData.fileName = null;
lessonData.fileDataUrl = null;
}
saveData();
}
};
// --- 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" style="display: ${quizTypeSelect.value === 'multiple-choice' ? 'block' : 'none'};">
<label>Choices:</label><br>
<input type="text" name="question-${currentQIndex}-choice-1" placeholder="Choice 1" value="${qChoices[0] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-2" placeholder="Choice 2" value="${qChoices[1] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-3" placeholder="Choice 3" value="${qChoices[2] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-4" placeholder="Choice 4" value="${qChoices[3] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
</div>
<label for="question-${currentQIndex}-correct-answer">${quizTypeSelect.value === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):'}</label>
<input type="text" name="question-${currentQIndex}-correct-answer" value="${qAnswer}" required><br>
`;
questionsContainer.appendChild(questionDiv);
if (!questionData) questionCount = currentQIndex;
};
const updateCreatedQuizzes = () => {
const quizzes = getData(storageKeys.quizzes);
createdQuizzesDiv.innerHTML = '';
quizzes.forEach((quiz, index) => {
const quizDiv = document.createElement('div');
const contentDiv = document.createElement('div');
const title = quiz.quizTitle || 'Untitled Quiz';
const type = quiz.quizType || 'N/A';
const numQuestions = Array.isArray(quiz.questions) ? quiz.questions.length : 0;
const dueDate = quiz.dueDate ? `Due: ${quiz.dueDate}` : '';
contentDiv.innerHTML = `<p><strong>${title}</strong></p><p>(Type: ${type}, Questions: ${numQuestions})</p><p>${dueDate}</p>`;
quizDiv.appendChild(contentDiv);
createdQuizzesDiv.appendChild(quizDiv);
});
updateDeleteChoices();
populateQuizSelectForScores();
};
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;
quizDueDateInput.value = quiz.dueDate || '';
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 quizDueDate = quizDueDateInput.value;
const questions = [];
const questionElements = questionsContainer.querySelectorAll('.question-container');
const currentQuestionCount = questionElements.length;
// Check if due date is in the past
if (quizDueDate) {
const now = new Date();
const dueDate = new Date(quizDueDate);
if (dueDate < now) {
alert('Due date cannot be in the past.');
return;
}
}
for (let i = 0; i < currentQuestionCount; i++) {
const qContainer = questionElements[i];
const qIndex = qContainer.dataset.qIndex;
const questionText = qContainer.querySelector(`[name='question-${qIndex}']`)?.value.trim();
const correctAnswer = qContainer.querySelector(`[name='question-${qIndex}-correct-answer']`)?.value.trim();
const choices = [];
if (!questionText || correctAnswer === undefined || correctAnswer === null || correctAnswer === "") {
alert(`Please fill out question text and correct answer for Question ${qIndex}.`);
return;
}
if (quizType === 'multiple-choice') {
const choiceInputs = qContainer.querySelectorAll(`.multiple-choice-container input[type="text"]`);
let choicesComplete = true;
choiceInputs.forEach(input => {
const choiceValue = input.value.trim();
if (!choiceValue) choicesComplete = false;
choices.push(choiceValue);
});
if (!choicesComplete) {
alert(`Please fill out all choices for Question ${qIndex}.`);
return;
}
if (!choices.includes(correctAnswer)) {
alert(`The correct answer for Question ${qIndex} ("${correctAnswer}") must exactly match one of the provided choices.`);
return;
}
}
questions.push({ questionText, choices: quizType === 'multiple-choice' ? choices : [], correctAnswer });
}
if (questions.length === 0) {
alert('Please add at least one question to the quiz.');
return;
}
const quizData = {
quizType,
quizTitle,
questions,
dueDate: quizDueDate,
createdAt: new Date().toISOString()
};
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();
notifyStudents('quiz', quizData);
};
// --- Delete Functions ---
const updateDeleteChoices = () => {
const deleteType = deleteTypeSelect.value;
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
const items = getData(
deleteType === "lesson" ? storageKeys.lessons :
deleteType === "quiz" ? storageKeys.quizzes :
storageKeys.assignments
);
items.forEach((item, index) => {
const option = document.createElement('option');
option.value = index;
option.textContent = item.title || item.quizTitle || `${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} ${index + 1}`;
deleteChoiceSelect.appendChild(option);
});
deleteBtn.disabled = items.length === 0;
};
const handleDelete = () => {
const selectedIndex = deleteChoiceSelect.value;
const deleteType = deleteTypeSelect.value;
if (selectedIndex === "") {
alert('Please select an item to delete.');
return;
}
const storageKey =
deleteType === 'lesson' ? storageKeys.lessons :
deleteType === 'quiz' ? storageKeys.quizzes :
storageKeys.assignments;
let items = getData(storageKey);
const itemToDelete = items[selectedIndex];
const itemName = itemToDelete?.title || itemToDelete?.quizTitle || `${deleteType} ${parseInt(selectedIndex)+1}`;
if (confirm(`Are you sure you want to delete ${deleteType} "${itemName}"? This cannot be undone.`)) {
items.splice(selectedIndex, 1);
setData(storageKey, items);
alert(`${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} Deleted!`);
if (deleteType === 'lesson') {
updateCreatedLessons();
} else if (deleteType === 'quiz') {
updateCreatedQuizzes();
} else {
updateCreatedAssignments();
}
closeModal(deleteModal);
}
};
// --- 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 || `Quiz ${index + 1}`;
quizSelectForScores.appendChild(option);
});
};
const displayStudentScores = () => {
const selectedQuizIndex = quizSelectForScores.value;
studentScoresDisplay.innerHTML = '';
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 || !selectedQuiz.quizTitle) {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Error: Could not find selected quiz data.</p>';
return;
}
const selectedQuizTitle = selectedQuiz.quizTitle;
const registeredUsers = getUsers();
if (Object.keys(registeredUsers).length === 0) {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered users found.</p>';
return;
}
const studentUsernames = Object.keys(registeredUsers).filter(username => {
const user = registeredUsers[username];
return user && user.role === 'student';
});
if (studentUsernames.length === 0) {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered students found.</p>';
return;
}
let tableHTML = `
<h4>Scores for: ${selectedQuizTitle}</h4>
<table>
<thead>
<tr>
<th>Student</th>
<th>Score (%)</th>
<th>Date Taken</th>
</tr>
</thead>
<tbody>
`;
let scoresFound = false;
studentUsernames.forEach(username => {
const studentData = registeredUsers[username];
if (studentData && Array.isArray(studentData.quizScores)) {
const result = studentData.quizScores.find(score => score.quizName === selectedQuizTitle);
if (result && typeof result.score === 'number') {
scoresFound = true;
const scorePercentage = result.score;
const dateTaken = result.timestamp ? new Date(result.timestamp).toLocaleString() : 'N/A';
tableHTML += `
<tr>
<td>${username}</td>
<td>${scorePercentage}%</td>
<td>${dateTaken}</td>
</tr>
`;
}
}
});
if (!scoresFound) {
tableHTML += '<tr><td colspan="3" class="no-scores-message">No students have taken this quiz yet or results are missing.</td></tr>';
}
tableHTML += '</tbody></table>';
studentScoresDisplay.innerHTML = tableHTML;
};
// --- Analytics Modal Functions ---
const openAnalyticsModal = () => {
populateTeacherAnalytics();
openModal(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 = getUsers();
const studentUsernames = Object.keys(registeredUsers).filter(username => registeredUsers[username]?.role === 'student');
studentUsernames.forEach(username => {
const studentData = registeredUsers[username];
if (studentData && Array.isArray(studentData.quizScores)) {
studentData.quizScores.forEach(result => {
if (result && typeof result.score === 'number') {
totalPercentageSum += result.score;
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 ---
createLessonBtn.addEventListener('click', () => { resetLessonForm(); openModal(lessonModal); });
closeRespondentsModal.addEventListener('click', () => {
closeModal(respondentsModal);
});
createQuizBtn.addEventListener('click', () => { resetQuizForm(); addQuestion(); openModal(quizModal); });
createAssignmentBtn.addEventListener('click', () => { resetAssignmentForm(); openModal(assignmentModal); });
deleteLessonBtn.addEventListener('click', () => {
deleteTypeSelect.value = "lesson";
updateDeleteChoices();
openModal(deleteModal);
});
deleteQuizBtn.addEventListener('click', () => {
deleteTypeSelect.value = "quiz";
updateDeleteChoices();
openModal(deleteModal);
});
deleteAssignmentBtn.addEventListener('click', () => {
deleteTypeSelect.value = "assignments";
updateDeleteChoices();
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);
}
});
lessonForm.addEventListener('submit', handleLessonFormSubmit);
quizForm.addEventListener('submit', handleQuizFormSubmit);
assignmentForm.addEventListener('submit', handleAssignmentFormSubmit);
addQuestionBtn.addEventListener('click', () => addQuestion());
quizTypeSelect.addEventListener('change', toggleMultipleChoiceFields);
deleteTypeSelect.addEventListener('change', updateDeleteChoices);
deleteBtn.addEventListener('click', handleDelete);
quizSelectForScores.addEventListener('change', displayStudentScores);
analyticsBtn.addEventListener('click', openAnalyticsModal);
modalDashboardBtn.addEventListener('click', () => closeModal(analyticsModal));
modalHomeBtn.addEventListener('click', goToHomepage);
modalLogoutBtn.addEventListener('click', logout);
// --- Initial Load ---
updateCreatedLessons();
updateCreatedQuizzes();
updateCreatedAssignments();
});