Okay, I will set up the project structure with the provided HTML, CSS, and JavaScript code for the Teacher and Student dashboards. I'll also create placeholder files for login.html, login.js, and homepage.html as they are referenced in the code.
This setup uses localStorage to share data (lessons, quizzes, user information) between the teacher and student views and sessionStorage to manage the logged-in user's state.
<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>
<!-- Options populated by JS -->
</select>
<div id="studentScoresDisplay" class="scores-display-area">
<p class="no-scores-message">Select a quiz to view student scores.</p>
<!-- Table will be inserted here by JS -->
</div>
</div>
</div>
</div>
<!-- Performance Analytics Button -->
<button id="analyticsBtn" class="analytics-btn">View Performance & Analytics</button>
<!-- Performance Analytics Fullscreen Modal -->
<div id="analyticsModal" class="modal fullscreen">
<div class="modal-content">
<h2>Teacher Performance & Analytics</h2>
<div class="analytics-section">
<h3>Overview</h3>
<p><strong>Lessons Created:</strong> <span id="lessonCount">0</span></p>
<p><strong>Quizzes Created:</strong> <span id="quizCount">0</span></p>
</div>
<div class="analytics-section">
<h3>Class Performance (Example)</h3>
<p>Average Quiz Score: <span id="averageQuizScore">N/A</span></p>
<!-- More detailed class performance could go here -->
</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="login.js"></script> <!-- Include for getUsers -->
<script src="teacher.js"></script>
</body>
</html>
<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>
<!-- Options populated by JS -->
</select>
<div id="studentScoresDisplay" class="scores-display-area">
<p class="no-scores-message">Select a quiz to view student scores.</p>
<!-- Table will be inserted here by JS -->
</div>
</div>
</div>
</div>
<!-- Performance Analytics Button -->
<button id="analyticsBtn" class="analytics-btn">View Performance & Analytics</button>
<!-- Performance Analytics Fullscreen Modal -->
<div id="analyticsModal" class="modal fullscreen">
<div class="modal-content">
<h2>Teacher Performance & Analytics</h2>
<div class="analytics-section">
<h3>Overview</h3>
<p><strong>Lessons Created:</strong> <span id="lessonCount">0</span></p>
<p><strong>Quizzes Created:</strong> <span id="quizCount">0</span></p>
</div>
<div class="analytics-section">
<h3>Class Performance (Example)</h3>
<p>Average Quiz Score: <span id="averageQuizScore">N/A</span></p>
<!-- More detailed class performance could go here -->
</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="login.js"></script> <!-- Include for getUsers -->
<script src="teacher.js"></script>
</body>
</html>
.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 */
}
.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 */
}
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'teacher') {
alert('Access denied. Please log in as a teacher.');
window.location.href = 'login.html'; // Redirect to login if not a teacher
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const lessonModal = document.getElementById('lessonModal');
const quizModal = document.getElementById('quizModal');
const deleteModal = document.getElementById('deleteModal');
const manageScoresModal = document.getElementById('manageScoresModal');
const analyticsModal = document.getElementById('analyticsModal');
const createLessonBtn = document.getElementById('createLessonBtn');
const createQuizBtn = document.getElementById('createQuizBtn');
const deleteLessonBtn = document.getElementById('deleteLessonBtn');
const deleteQuizBtn = document.getElementById('deleteQuizBtn');
const manageScoresBtn = document.getElementById('manageScoresBtn');
const analyticsBtn = document.getElementById('analyticsBtn');
const closeButtons = document.querySelectorAll('.close');
// Lesson Form Elements
const lessonForm = document.getElementById('lessonForm');
const lessonModalTitle = document.getElementById('lessonModalTitle');
const editLessonIndexInput = document.getElementById('editLessonIndex');
const lessonTitleInput = document.getElementById('lessonTitle');
const lessonContentInput = document.getElementById('lessonContent');
const lessonSubmitBtn = document.getElementById('lessonSubmitBtn');
// Quiz Form Elements
const quizForm = document.getElementById('quizForm');
const quizModalTitle = document.getElementById('quizModalTitle');
const editQuizIndexInput = document.getElementById('editQuizIndex');
const quizTypeSelect = document.getElementById('quizType');
const quizTitleInput = document.getElementById('quizTitle');
const questionsContainer = document.getElementById('questionsContainer');
const addQuestionBtn = document.getElementById('addQuestionBtn');
const quizSubmitBtn = document.getElementById('quizSubmitBtn');
// Delete Modal Elements
const deleteTypeSelect = document.getElementById('deleteType');
const deleteChoiceSelect = document.getElementById('deleteChoice');
const deleteBtn = document.getElementById('deleteBtn');
// Manage Scores Modal Elements
const quizSelectForScores = document.getElementById('quizSelectForScores');
const studentScoresDisplay = document.getElementById('studentScoresDisplay');
// Analytics Modal Elements
const lessonCountSpan = document.getElementById('lessonCount');
const quizCountSpan = document.getElementById('quizCount');
const averageQuizScoreSpan = document.getElementById('averageQuizScore');
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// Display Areas
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
let questionCount = 0;
const storageKeys = {
lessons: 'createdLessons',
quizzes: 'createdQuizzes',
users: 'registeredUsers' // Key for all registered users (replaces studentResultPrefix)
};
// --- Utility Functions ---
const openModal = (modal) => {
modal.style.display = "block";
if (modal.classList.contains('fullscreen')) {
document.body.classList.add('modal-open');
}
};
const closeModal = (modal) => {
modal.style.display = "none";
if (modal.classList.contains('fullscreen')) {
document.body.classList.remove('modal-open');
}
// Reset forms/content on modal close
if (modal.id === 'lessonModal') resetLessonForm();
if (modal.id === 'quizModal') resetQuizForm();
if (modal.id === 'manageScoresModal') {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
quizSelectForScores.value = "";
}
if (modal.id === 'deleteModal') {
deleteTypeSelect.value = 'lesson';
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
}
};
// Gets array data (lessons, quizzes)
const getData = (key) => {
const data = localStorage.getItem(key);
if (data && data.startsWith('[')) {
try {
return JSON.parse(data);
} catch (e) {
console.error("Error parsing JSON array from localStorage for key:", key, e);
return [];
}
}
return [];
};
// Gets object data (registered users) - Reusing getUsers from login.js
// const getObjectData = (key) => { ... } // Replaced by getUsers() from login.js
const setData = (key, data) => {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (e) {
console.error("Error setting data to localStorage for key:", key, e);
}
};
// --- Lesson Functions ---
const resetLessonForm = () => {
lessonForm.reset();
editLessonIndexInput.value = "-1";
lessonModalTitle.textContent = "Create Lesson";
lessonSubmitBtn.textContent = "Create Lesson";
};
const updateCreatedLessons = () => {
const lessons = getData(storageKeys.lessons);
createdLessonsDiv.innerHTML = '';
lessons.forEach((lesson, index) => {
const lessonDiv = document.createElement('div');
const contentDiv = document.createElement('div');
contentDiv.innerHTML = `<p><strong>${lesson.title}</strong></p><p>${lesson.content.substring(0, 100)}${lesson.content.length > 100 ? '...' : ''}</p>`;
lessonDiv.appendChild(contentDiv);
const editBtn = document.createElement('button');
editBtn.textContent = 'Edit';
editBtn.classList.add('btn', 'edit');
editBtn.dataset.index = index;
editBtn.addEventListener('click', () => editLesson(index));
lessonDiv.appendChild(editBtn);
createdLessonsDiv.appendChild(lessonDiv);
});
updateDeleteChoices(); // Update delete dropdown after lessons update
};
const editLesson = (index) => {
const lessons = getData(storageKeys.lessons);
if (index >= 0 && index < lessons.length) {
const lesson = lessons[index];
resetLessonForm();
editLessonIndexInput.value = index;
lessonTitleInput.value = lesson.title;
lessonContentInput.value = lesson.content;
lessonModalTitle.textContent = "Edit Lesson";
lessonSubmitBtn.textContent = "Save Changes";
openModal(lessonModal);
}
};
const handleLessonFormSubmit = (event) => {
event.preventDefault();
const lessonData = {
title: lessonTitleInput.value,
content: lessonContentInput.value,
};
const editIndex = parseInt(editLessonIndexInput.value, 10);
let lessons = getData(storageKeys.lessons);
if (editIndex > -1 && editIndex < lessons.length) {
lessons[editIndex] = lessonData;
alert('Lesson Updated!');
} else {
lessons.push(lessonData);
alert('Lesson Created!');
}
setData(storageKeys.lessons, lessons);
closeModal(lessonModal);
updateCreatedLessons();
};
// --- Quiz Functions ---
const resetQuizForm = () => {
quizForm.reset();
editQuizIndexInput.value = "-1";
questionsContainer.innerHTML = '';
questionCount = 0;
quizModalTitle.textContent = "Create Quiz";
quizSubmitBtn.textContent = "Create Quiz";
quizTypeSelect.disabled = false; // Re-enable type select
toggleMultipleChoiceFields(); // Ensure fields match default type
};
const toggleMultipleChoiceFields = () => {
const selectedType = quizTypeSelect.value;
const allQuestionContainers = questionsContainer.querySelectorAll('.question-container');
allQuestionContainers.forEach(qContainer => {
const mcContainer = qContainer.querySelector('.multiple-choice-container');
const choiceInputs = mcContainer ? mcContainer.querySelectorAll('input[type="text"]') : [];
const answerInput = qContainer.querySelector('input[name$="-correct-answer"]');
const answerLabel = answerInput ? answerInput.previousElementSibling : null;
if (mcContainer) {
mcContainer.style.display = selectedType === 'multiple-choice' ? 'block' : 'none';
// Set required only if multiple choice is selected
choiceInputs.forEach(input => input.required = (selectedType === 'multiple-choice'));
}
if (answerLabel && answerLabel.tagName === 'LABEL') {
answerLabel.textContent = selectedType === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):';
}
});
};
const addQuestion = (questionData = null) => {
const currentQIndex = questionData ? questionData.qIndex : ++questionCount;
const questionDiv = document.createElement('div');
questionDiv.classList.add('question-container');
questionDiv.dataset.qIndex = currentQIndex;
const qText = questionData ? questionData.questionText : '';
const qAnswer = questionData ? questionData.correctAnswer : '';
const qChoices = questionData ? questionData.choices : ['', '', '', '']; // Default empty choices
questionDiv.innerHTML = `
<h4>Question ${currentQIndex}</h4>
<label for="question-${currentQIndex}">Question Text:</label>
<input type="text" id="question-${currentQIndex}" name="question-${currentQIndex}" value="${qText}" required><br>
<div class="multiple-choice-container" style="display: ${quizTypeSelect.value === 'multiple-choice' ? 'block' : 'none'};">
<label>Choices:</label><br>
<input type="text" name="question-${currentQIndex}-choice-1" placeholder="Choice 1" value="${qChoices[0] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-2" placeholder="Choice 2" value="${qChoices[1] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-3" placeholder="Choice 3" value="${qChoices[2] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-4" placeholder="Choice 4" value="${qChoices[3] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
</div>
<label for="question-${currentQIndex}-correct-answer">${quizTypeSelect.value === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):'}</label>
<input type="text" name="question-${currentQIndex}-correct-answer" value="${qAnswer}" required><br>
`;
questionsContainer.appendChild(questionDiv);
if (!questionData) questionCount = currentQIndex; // Update global count only for new questions
// No need to call toggleMultipleChoiceFields here as it's called on type change and form reset
};
const updateCreatedQuizzes = () => {
const quizzes = getData(storage
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'teacher') {
alert('Access denied. Please log in as a teacher.');
window.location.href = 'login.html'; // Redirect to login if not a teacher
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const lessonModal = document.getElementById('lessonModal');
const quizModal = document.getElementById('quizModal');
const deleteModal = document.getElementById('deleteModal');
const manageScoresModal = document.getElementById('manageScoresModal');
const analyticsModal = document.getElementById('analyticsModal');
const createLessonBtn = document.getElementById('createLessonBtn');
const createQuizBtn = document.getElementById('createQuizBtn');
const deleteLessonBtn = document.getElementById('deleteLessonBtn');
const deleteQuizBtn = document.getElementById('deleteQuizBtn');
const manageScoresBtn = document.getElementById('manageScoresBtn');
const analyticsBtn = document.getElementById('analyticsBtn');
const closeButtons = document.querySelectorAll('.close');
// Lesson Form Elements
const lessonForm = document.getElementById('lessonForm');
const lessonModalTitle = document.getElementById('lessonModalTitle');
const editLessonIndexInput = document.getElementById('editLessonIndex');
const lessonTitleInput = document.getElementById('lessonTitle');
const lessonContentInput = document.getElementById('lessonContent');
const lessonSubmitBtn = document.getElementById('lessonSubmitBtn');
// Quiz Form Elements
const quizForm = document.getElementById('quizForm');
const quizModalTitle = document.getElementById('quizModalTitle');
const editQuizIndexInput = document.getElementById('editQuizIndex');
const quizTypeSelect = document.getElementById('quizType');
const quizTitleInput = document.getElementById('quizTitle');
const questionsContainer = document.getElementById('questionsContainer');
const addQuestionBtn = document.getElementById('addQuestionBtn');
const quizSubmitBtn = document.getElementById('quizSubmitBtn');
// Delete Modal Elements
const deleteTypeSelect = document.getElementById('deleteType');
const deleteChoiceSelect = document.getElementById('deleteChoice');
const deleteBtn = document.getElementById('deleteBtn');
// Manage Scores Modal Elements
const quizSelectForScores = document.getElementById('quizSelectForScores');
const studentScoresDisplay = document.getElementById('studentScoresDisplay');
// Analytics Modal Elements
const lessonCountSpan = document.getElementById('lessonCount');
const quizCountSpan = document.getElementById('quizCount');
const averageQuizScoreSpan = document.getElementById('averageQuizScore');
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// Display Areas
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
let questionCount = 0;
const storageKeys = {
lessons: 'createdLessons',
quizzes: 'createdQuizzes',
users: 'registeredUsers' // Key for all registered users (replaces studentResultPrefix)
};
// --- Utility Functions ---
const openModal = (modal) => {
modal.style.display = "block";
if (modal.classList.contains('fullscreen')) {
document.body.classList.add('modal-open');
}
};
const closeModal = (modal) => {
modal.style.display = "none";
if (modal.classList.contains('fullscreen')) {
document.body.classList.remove('modal-open');
}
// Reset forms/content on modal close
if (modal.id === 'lessonModal') resetLessonForm();
if (modal.id === 'quizModal') resetQuizForm();
if (modal.id === 'manageScoresModal') {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
quizSelectForScores.value = "";
}
if (modal.id === 'deleteModal') {
deleteTypeSelect.value = 'lesson';
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
}
};
// Gets array data (lessons, quizzes)
const getData = (key) => {
const data = localStorage.getItem(key);
if (data && data.startsWith('[')) {
try {
return JSON.parse(data);
} catch (e) {
console.error("Error parsing JSON array from localStorage for key:", key, e);
return [];
}
}
return [];
};
// Gets object data (registered users) - Reusing getUsers from login.js
// const getObjectData = (key) => { ... } // Replaced by getUsers() from login.js
const setData = (key, data) => {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (e) {
console.error("Error setting data to localStorage for key:", key, e);
}
};
// --- Lesson Functions ---
const resetLessonForm = () => {
lessonForm.reset();
editLessonIndexInput.value = "-1";
lessonModalTitle.textContent = "Create Lesson";
lessonSubmitBtn.textContent = "Create Lesson";
};
const updateCreatedLessons = () => {
const lessons = getData(storageKeys.lessons);
createdLessonsDiv.innerHTML = '';
lessons.forEach((lesson, index) => {
const lessonDiv = document.createElement('div');
const contentDiv = document.createElement('div');
contentDiv.innerHTML = `<p><strong>${lesson.title}</strong></p><p>${lesson.content.substring(0, 100)}${lesson.content.length > 100 ? '...' : ''}</p>`;
lessonDiv.appendChild(contentDiv);
const editBtn = document.createElement('button');
editBtn.textContent = 'Edit';
editBtn.classList.add('btn', 'edit');
editBtn.dataset.index = index;
editBtn.addEventListener('click', () => editLesson(index));
lessonDiv.appendChild(editBtn);
createdLessonsDiv.appendChild(lessonDiv);
});
updateDeleteChoices(); // Update delete dropdown after lessons update
};
const editLesson = (index) => {
const lessons = getData(storageKeys.lessons);
if (index >= 0 && index < lessons.length) {
const lesson = lessons[index];
resetLessonForm();
editLessonIndexInput.value = index;
lessonTitleInput.value = lesson.title;
lessonContentInput.value = lesson.content;
lessonModalTitle.textContent = "Edit Lesson";
lessonSubmitBtn.textContent = "Save Changes";
openModal(lessonModal);
}
};
const handleLessonFormSubmit = (event) => {
event.preventDefault();
const lessonData = {
title: lessonTitleInput.value,
content: lessonContentInput.value,
};
const editIndex = parseInt(editLessonIndexInput.value, 10);
let lessons = getData(storageKeys.lessons);
if (editIndex > -1 && editIndex < lessons.length) {
lessons[editIndex] = lessonData;
alert('Lesson Updated!');
} else {
lessons.push(lessonData);
alert('Lesson Created!');
}
setData(storageKeys.lessons, lessons);
closeModal(lessonModal);
updateCreatedLessons();
};
// --- Quiz Functions ---
const resetQuizForm = () => {
quizForm.reset();
editQuizIndexInput.value = "-1";
questionsContainer.innerHTML = '';
questionCount = 0;
quizModalTitle.textContent = "Create Quiz";
quizSubmitBtn.textContent = "Create Quiz";
quizTypeSelect.disabled = false; // Re-enable type select
toggleMultipleChoiceFields(); // Ensure fields match default type
};
const toggleMultipleChoiceFields = () => {
const selectedType = quizTypeSelect.value;
const allQuestionContainers = questionsContainer.querySelectorAll('.question-container');
allQuestionContainers.forEach(qContainer => {
const mcContainer = qContainer.querySelector('.multiple-choice-container');
const choiceInputs = mcContainer ? mcContainer.querySelectorAll('input[type="text"]') : [];
const answerInput = qContainer.querySelector('input[name$="-correct-answer"]');
const answerLabel = answerInput ? answerInput.previousElementSibling : null;
if (mcContainer) {
mcContainer.style.display = selectedType === 'multiple-choice' ? 'block' : 'none';
// Set required only if multiple choice is selected
choiceInputs.forEach(input => input.required = (selectedType === 'multiple-choice'));
}
if (answerLabel && answerLabel.tagName === 'LABEL') {
answerLabel.textContent = selectedType === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):';
}
});
};
const addQuestion = (questionData = null) => {
const currentQIndex = questionData ? questionData.qIndex : ++questionCount;
const questionDiv = document.createElement('div');
questionDiv.classList.add('question-container');
questionDiv.dataset.qIndex = currentQIndex;
const qText = questionData ? questionData.questionText : '';
const qAnswer = questionData ? questionData.correctAnswer : '';
const qChoices = questionData ? questionData.choices : ['', '', '', '']; // Default empty choices
questionDiv.innerHTML = `
<h4>Question ${currentQIndex}</h4>
<label for="question-${currentQIndex}">Question Text:</label>
<input type="text" id="question-${currentQIndex}" name="question-${currentQIndex}" value="${qText}" required><br>
<div class="multiple-choice-container" style="display: ${quizTypeSelect.value === 'multiple-choice' ? 'block' : 'none'};">
<label>Choices:</label><br>
<input type="text" name="question-${currentQIndex}-choice-1" placeholder="Choice 1" value="${qChoices[0] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-2" placeholder="Choice 2" value="${qChoices[1] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-3" placeholder="Choice 3" value="${qChoices[2] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-4" placeholder="Choice 4" value="${qChoices[3] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
</div>
<label for="question-${currentQIndex}-correct-answer">${quizTypeSelect.value === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):'}</label>
<input type="text" name="question-${currentQIndex}-correct-answer" value="${qAnswer}" required><br>
`;
questionsContainer.appendChild(questionDiv);
if (!questionData) questionCount = currentQIndex; // Update global count only for new questions
// No need to call toggleMultipleChoiceFields here as it's called on type change and form reset
};
const updateCreatedQuizzes = () => {
const quizzes = getData(storage
Okay, here is the complete code for the Teacher and Student dashboards, including the full JavaScript files and the necessary placeholder files for login and homepage functionality.
<jitProject id="teacher-student-dashboard-full" title="Teacher and Student Dashboards (Full Code)"> <jitFile type="file" filePath="teacher.html"> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Teacher Dashboard</title> <link rel="stylesheet" href="teacher.css"> </head> <body> <div class="navbar">
<h1>Teacher Dashboard</h1>
</div>
<div class="container">
<div class="button-container">
<button class="btn" id="createLessonBtn">Create Lesson</button>
<button class="btn" id="createQuizBtn">Make Quiz</button>
<button class="btn" id="manageScoresBtn">Manage Scores & Grades</button>
<button class="btn" id="deleteLessonBtn">Delete Lesson</button>
<button class="btn" id="deleteQuizBtn">Delete Quiz</button> <!-- 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>
<!-- Options populated by JS -->
</select>
<div id="studentScoresDisplay" class="scores-display-area">
<p class="no-scores-message">Select a quiz to view student scores.</p>
<!-- Table will be inserted here by JS -->
</div>
</div>
</div>
</div>
<!-- Performance Analytics Button -->
<button id="analyticsBtn" class="analytics-btn">View Performance & Analytics</button>
<!-- Performance Analytics Fullscreen Modal -->
<div id="analyticsModal" class="modal fullscreen">
<div class="modal-content">
<h2>Teacher Performance & Analytics</h2>
<div class="analytics-section">
<h3>Overview</h3>
<p><strong>Lessons Created:</strong> <span id="lessonCount">0</span></p>
<p><strong>Quizzes Created:</strong> <span id="quizCount">0</span></p>
</div>
<div class="analytics-section">
<h3>Class Performance</h3>
<p>Average Quiz Score (across all students/quizzes): <span id="averageQuizScore">N/A</span></p>
<!-- More detailed class performance could go here -->
</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="login.js"></script> <!-- Include for getUsers -->
<script src="teacher.js"></script>
</body>
</html>
<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>
<!-- Options populated by JS -->
</select>
<div id="studentScoresDisplay" class="scores-display-area">
<p class="no-scores-message">Select a quiz to view student scores.</p>
<!-- Table will be inserted here by JS -->
</div>
</div>
</div>
</div>
<!-- Performance Analytics Button -->
<button id="analyticsBtn" class="analytics-btn">View Performance & Analytics</button>
<!-- Performance Analytics Fullscreen Modal -->
<div id="analyticsModal" class="modal fullscreen">
<div class="modal-content">
<h2>Teacher Performance & Analytics</h2>
<div class="analytics-section">
<h3>Overview</h3>
<p><strong>Lessons Created:</strong> <span id="lessonCount">0</span></p>
<p><strong>Quizzes Created:</strong> <span id="quizCount">0</span></p>
</div>
<div class="analytics-section">
<h3>Class Performance</h3>
<p>Average Quiz Score (across all students/quizzes): <span id="averageQuizScore">N/A</span></p>
<!-- More detailed class performance could go here -->
</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="login.js"></script> <!-- Include for getUsers -->
<script src="teacher.js"></script>
</body>
</html>
.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 */
}
.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 */
}
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'teacher') {
alert('Access denied. Please log in as a teacher.');
window.location.href = 'login.html'; // Redirect to login if not a teacher
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const lessonModal = document.getElementById('lessonModal');
const quizModal = document.getElementById('quizModal');
const deleteModal = document.getElementById('deleteModal');
const manageScoresModal = document.getElementById('manageScoresModal');
const analyticsModal = document.getElementById('analyticsModal');
const createLessonBtn = document.getElementById('createLessonBtn');
const createQuizBtn = document.getElementById('createQuizBtn');
const deleteLessonBtn = document.getElementById('deleteLessonBtn');
const deleteQuizBtn = document.getElementById('deleteQuizBtn');
const manageScoresBtn = document.getElementById('manageScoresBtn');
const analyticsBtn = document.getElementById('analyticsBtn');
const closeButtons = document.querySelectorAll('.close');
// Lesson Form Elements
const lessonForm = document.getElementById('lessonForm');
const lessonModalTitle = document.getElementById('lessonModalTitle');
const editLessonIndexInput = document.getElementById('editLessonIndex');
const lessonTitleInput = document.getElementById('lessonTitle');
const lessonContentInput = document.getElementById('lessonContent');
const lessonSubmitBtn = document.getElementById('lessonSubmitBtn');
// Quiz Form Elements
const quizForm = document.getElementById('quizForm');
const quizModalTitle = document.getElementById('quizModalTitle');
const editQuizIndexInput = document.getElementById('editQuizIndex');
const quizTypeSelect = document.getElementById('quizType');
const quizTitleInput = document.getElementById('quizTitle');
const questionsContainer = document.getElementById('questionsContainer');
const addQuestionBtn = document.getElementById('addQuestionBtn');
const quizSubmitBtn = document.getElementById('quizSubmitBtn');
// Delete Modal Elements
const deleteTypeSelect = document.getElementById('deleteType');
const deleteChoiceSelect = document.getElementById('deleteChoice');
const deleteBtn = document.getElementById('deleteBtn');
// Manage Scores Modal Elements
const quizSelectForScores = document.getElementById('quizSelectForScores');
const studentScoresDisplay = document.getElementById('studentScoresDisplay');
// Analytics Modal Elements
const lessonCountSpan = document.getElementById('lessonCount');
const quizCountSpan = document.getElementById('quizCount');
const averageQuizScoreSpan = document.getElementById('averageQuizScore');
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// Display Areas
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
let questionCount = 0;
const storageKeys = {
lessons: 'createdLessons',
quizzes: 'createdQuizzes',
users: 'registeredUsers' // Key for all registered users (replaces studentResultPrefix)
};
// --- Utility Functions ---
const openModal = (modal) => {
modal.style.display = "block";
if (modal.classList.contains('fullscreen')) {
document.body.classList.add('modal-open');
}
};
const closeModal = (modal) => {
modal.style.display = "none";
if (modal.classList.contains('fullscreen')) {
document.body.classList.remove('modal-open');
}
// Reset forms/content on modal close
if (modal.id === 'lessonModal') resetLessonForm();
if (modal.id === 'quizModal') resetQuizForm();
if (modal.id === 'manageScoresModal') {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
quizSelectForScores.value = "";
}
if (modal.id === 'deleteModal') {
deleteTypeSelect.value = 'lesson';
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
}
};
// Gets array data (lessons, quizzes)
const getData = (key) => {
const data = localStorage.getItem(key);
if (data && data.startsWith('[')) {
try {
return JSON.parse(data);
} catch (e) {
console.error("Error parsing JSON array from localStorage for key:", key, e);
return [];
}
}
return [];
};
// Gets object data (registered users) - Reusing getUsers from login.js
// Ensure login.js is loaded first and getUsers is available globally
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.");
// Optionally disable functionality or redirect
return;
}
const setData = (key, data) => {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (e) {
console.error("Error setting data to localStorage for key:", key, e);
}
};
// --- Lesson Functions ---
const resetLessonForm = () => {
lessonForm.reset();
editLessonIndexInput.value = "-1";
lessonModalTitle.textContent = "Create Lesson";
lessonSubmitBtn.textContent = "Create Lesson";
};
const updateCreatedLessons = () => {
const lessons = getData(storageKeys.lessons);
createdLessonsDiv.innerHTML = '';
lessons.forEach((lesson, index) => {
const lessonDiv = document.createElement('div');
const contentDiv = document.createElement('div');
contentDiv.innerHTML = `<p><strong>${lesson.title}</strong></p><p>${lesson.content.substring(0, 100)}${lesson.content.length > 100 ? '...' : ''}</p>`;
lessonDiv.appendChild(contentDiv);
const editBtn = document.createElement('button');
editBtn.textContent = 'Edit';
editBtn.classList.add('btn', 'edit');
editBtn.dataset.index = index;
editBtn.addEventListener('click', () => editLesson(index));
lessonDiv.appendChild(editBtn);
createdLessonsDiv.appendChild(lessonDiv);
});
updateDeleteChoices(); // Update delete dropdown after lessons update
};
const editLesson = (index) => {
const lessons = getData(storageKeys.lessons);
if (index >= 0 && index < lessons.length) {
const lesson = lessons[index];
resetLessonForm();
editLessonIndexInput.value = index;
lessonTitleInput.value = lesson.title;
lessonContentInput.value = lesson.content;
lessonModalTitle.textContent = "Edit Lesson";
lessonSubmitBtn.textContent = "Save Changes";
openModal(lessonModal);
}
};
const handleLessonFormSubmit = (event) => {
event.preventDefault();
const lessonData = {
title: lessonTitleInput.value,
content: lessonContentInput.value,
};
const editIndex = parseInt(editLessonIndexInput.value, 10);
let lessons = getData(storageKeys.lessons);
if (editIndex > -1 && editIndex < lessons.length) {
lessons[editIndex] = lessonData;
alert('Lesson Updated!');
} else {
lessons.push(lessonData);
alert('Lesson Created!');
}
setData(storageKeys.lessons, lessons);
closeModal(lessonModal);
updateCreatedLessons();
};
// --- Quiz Functions ---
const resetQuizForm = () => {
quizForm.reset();
editQuizIndexInput.value = "-1";
questionsContainer.innerHTML = '';
questionCount = 0;
quizModalTitle.textContent = "Create Quiz";
quizSubmitBtn.textContent = "Create Quiz";
quizTypeSelect.disabled = false; // Re-enable type select
toggleMultipleChoiceFields(); // Ensure fields match default type
};
const toggleMultipleChoiceFields = () => {
const selectedType = quizTypeSelect.value;
const allQuestionContainers = questionsContainer.querySelectorAll('.question-container');
allQuestionContainers.forEach(qContainer => {
const mcContainer = qContainer.querySelector('.multiple-choice-container');
const choiceInputs = mcContainer ? mcContainer.querySelectorAll('input[type="text"]') : [];
const answerInput = qContainer.querySelector('input[name$="-correct-answer"]');
const answerLabel = answerInput ? answerInput.previousElementSibling : null;
if (mcContainer) {
mcContainer.style.display = selectedType === 'multiple-choice' ? 'block' : 'none';
// Set required only if multiple choice is selected
choiceInputs.forEach(input => input.required = (selectedType === 'multiple-choice'));
}
if (answerLabel && answerLabel.tagName === 'LABEL') {
answerLabel.textContent = selectedType === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):';
}
});
};
const addQuestion = (questionData = null) => {
const currentQIndex = questionData ? questionData.qIndex : ++questionCount;
const questionDiv = document.createElement('div');
questionDiv.classList.add('question-container');
questionDiv.dataset.qIndex = currentQIndex;
const qText = questionData ? questionData.questionText : '';
const qAnswer = questionData ? questionData.correctAnswer : '';
const qChoices = questionData ? questionData.choices : ['', '', '', '']; // Default empty choices
questionDiv.innerHTML = `
<h4>Question ${currentQIndex}</h4>
<label for="question-${currentQIndex}">Question Text:</label>
<input type="text" id="question-${currentQIndex}" name="question-${currentQIndex}" value="${qText}" required><br>
<div class="multiple-choice-container" style="display: ${quizTypeSelect.value === 'multiple-choice' ? 'block' : 'none'};">
<label>Choices:</label><br>
<input type="text" name="question-${currentQIndex}-choice-1" placeholder="Choice 1" value="${qChoices[0] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-2" placeholder="Choice 2" value="${qChoices[1] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-3" placeholder="Choice 3" value="${qChoices[2] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-4" placeholder="Choice 4" value="${qChoices[3] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
</div>
<label for="question-${currentQIndex}-correct-answer">${quizTypeSelect.value === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):'}</label>
<input type="text" name="question-${currentQIndex}-correct-answer" value="${qAnswer}" required><br>
`;
questionsContainer.appendChild(questionDiv);
if (!questionData) questionCount = currentQIndex; // Update global count only for new questions
// No need to call toggleMultipleChoiceFields here as it's called on type change and form reset
};
const updateCreatedQuizzes = () => {
const quizzes = getData(storageKeys.quizzes);
createdQuizzesDiv.innerHTML = '';
quizzes.forEach((quiz, index) => {
const quizDiv = document.createElement('div');
const contentDiv = document.createElement('div');
// Basic validation before displaying
const title = quiz.quizTitle || 'Untitled Quiz';
const type = quiz.quizType || 'N/A';
const numQuestions = Array.isArray(quiz.questions) ? quiz.questions.length : 0;
contentDiv.innerHTML = `<p><strong>${title}</strong></p><p>(Type: ${type}, Questions: ${numQuestions})</p>`;
quizDiv.appendChild(contentDiv);
// No Edit button for quizzes currently
createdQuizzesDiv.appendChild(quizDiv);
});
updateDeleteChoices(); // Update delete dropdown after quizzes update
populateQuizSelectForScores(); // Update scores dropdown after quizzes update
};
// Edit Quiz function remains but is not called from UI
const editQuiz = (index) => {
const quizzes = getData(storageKeys.quizzes);
if (index >= 0 && index < quizzes.length) {
const quiz = quizzes[index];
resetQuizForm();
editQuizIndexInput.value = index;
quizTitleInput.value = quiz.quizTitle;
quizTypeSelect.value = quiz.quizType;
quizTypeSelect.disabled = true; // Disable type change when editing
questionCount = 0; // Reset count for adding existing questions
quiz.questions.forEach((q, qIndex) => {
addQuestion({ ...q, qIndex: qIndex + 1 }); // Pass existing data
});
quizModalTitle.textContent = "Edit Quiz";
quizSubmitBtn.textContent = "Save Changes";
openModal(quizModal);
toggleMultipleChoiceFields(); // Ensure fields match loaded quiz type
}
};
const handleQuizFormSubmit = (event) => {
event.preventDefault();
const editIndex = parseInt(editQuizIndexInput.value, 10);
const quizType = quizTypeSelect.value;
const quizTitle = quizTitleInput.value;
const questions = [];
const questionElements = questionsContainer.querySelectorAll('.question-container');
const currentQuestionCount = questionElements.length; // Use actual number of question divs
for (let i = 0; i < currentQuestionCount; i++) {
const qContainer = questionElements[i];
const qIndex = qContainer.dataset.qIndex; // Get index from data attribute
const questionText = qContainer.querySelector(`[name='question-${qIndex}']`)?.value.trim();
const correctAnswer = qContainer.querySelector(`[name='question-${qIndex}-correct-answer']`)?.value.trim();
const choices = [];
if (!questionText || correctAnswer === undefined || correctAnswer === null || correctAnswer === "") {
alert(`Please fill out question text and correct answer for Question ${qIndex}.`);
return;
}
if (quizType === 'multiple-choice') {
const choiceInputs = qContainer.querySelectorAll(`.multiple-choice-container input[type="text"]`);
let choicesComplete = true;
choiceInputs.forEach(input => {
const choiceValue = input.value.trim();
if (!choiceValue) choicesComplete = false;
choices.push(choiceValue);
});
if (!choicesComplete) {
alert(`Please fill out all choices for Question ${qIndex}.`);
return;
}
// Ensure the correct answer is one of the choices provided
if (!choices.includes(correctAnswer)) {
alert(`The correct answer for Question ${qIndex} ("${correctAnswer}") must exactly match one of the provided choices.`);
return;
}
}
questions.push({ questionText, choices: quizType === 'multiple-choice' ? choices : [], correctAnswer });
}
if (questions.length === 0) {
alert('Please add at least one question to the quiz.');
return;
}
const quizData = { quizType, quizTitle, questions };
let quizzes = getData(storageKeys.quizzes);
if (editIndex > -1 && editIndex < quizzes.length) {
quizzes[editIndex] = quizData;
alert('Quiz Updated!');
} else {
quizzes.push(quizData);
alert('Quiz Created!');
}
setData(storageKeys.quizzes, quizzes);
closeModal(quizModal);
updateCreatedQuizzes();
};
// --- Delete Functions (Handles both Lessons and Quizzes) ---
const updateDeleteChoices = () => {
const deleteType = deleteTypeSelect.value; // Read the selected type
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
const items = getData(deleteType === "lesson" ? storageKeys.lessons : storageKeys.quizzes);
items.forEach((item, index) => {
const option = document.createElement('option');
option.value = index;
// Use 'title' for lessons and 'quizTitle' for quizzes, provide fallback
option.textContent = item.title || item.quizTitle || `${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} ${index + 1}`;
deleteChoiceSelect.appendChild(option);
});
deleteBtn.disabled = items.length === 0; // Disable button if no items
};
const handleDelete = () => {
const selectedIndex = deleteChoiceSelect.value;
const deleteType = deleteTypeSelect.value; // Get the type from the dropdown
if (selectedIndex === "") {
alert('Please select an item to delete.');
return;
}
const storageKey = deleteType === 'lesson' ? storageKeys.lessons : storageKeys.quizzes;
let items = getData(storageKey);
const itemToDelete = items[selectedIndex];
const itemName = itemToDelete?.title || itemToDelete?.quizTitle || `${deleteType} ${parseInt(selectedIndex)+1}`;
if (confirm(`Are you sure you want to delete ${deleteType} "${itemName}"? This cannot be undone.`)) {
items.splice(selectedIndex, 1);
setData(storageKey, items);
alert(`${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} Deleted!`);
// Update the correct display area
if (deleteType === 'lesson') {
updateCreatedLessons();
} else {
updateCreatedQuizzes(); // This also updates score/delete dropdowns
}
closeModal(deleteModal); // Close and reset the modal
}
};
// --- Manage Scores Functions ---
const populateQuizSelectForScores = () => {
const quizzes = getData(storageKeys.quizzes);
quizSelectForScores.innerHTML = '<option value="">-- Select a Quiz --</option>';
quizzes.forEach((quiz, index) => {
const option = document.createElement('option');
option.value = index; // Use the index as the value
option.textContent = quiz.quizTitle || `Quiz ${index + 1}`; // Fallback title
quizSelectForScores.appendChild(option);
});
};
const displayStudentScores = () => {
const selectedQuizIndex = quizSelectForScores.value;
studentScoresDisplay.innerHTML = ''; // Clear previous content
console.log(`[DEBUG] displayStudentScores called. Selected Quiz Index: '${selectedQuizIndex}'`);
if (selectedQuizIndex === "") {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
console.log("[DEBUG] No quiz selected. Aborting.");
return;
}
const quizzes = getData(storageKeys.quizzes);
const selectedQuiz = quizzes[selectedQuizIndex];
if (!selectedQuiz || !selectedQuiz.quizTitle) {
console.error(`[DEBUG] Error: Could not find valid quiz data or title for index ${selectedQuizIndex}`);
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Error: Could not find selected quiz data.</p>';
return;
}
const selectedQuizTitle = selectedQuiz.quizTitle;
console.log("[DEBUG] Selected Quiz Data:", selectedQuiz);
// --- Get ALL registered users ---
const registeredUsers = getUsers(); // Use function from login.js
console.log("[DEBUG] Raw Registered Users Data from getUsers():", registeredUsers);
if (Object.keys(registeredUsers).length === 0) {
console.warn("[DEBUG] No registered users found.");
studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered users found.</p>';
return;
}
// --- Filter for users with role 'student' ---
const studentUsernames = Object.keys(registeredUsers).filter(username => {
const user = registeredUsers[username];
const isStudent = user && user.role === 'student';
if (!isStudent) {
console.log(`[DEBUG] Filtering out user '${username}'. Role is not 'student' or user data is malformed. User data:`, user);
}
return isStudent;
});
console.log("[DEBUG] Filtered Student Usernames:", studentUsernames);
if (studentUsernames.length === 0) {
console.warn("[DEBUG] No users with role 'student' found after filtering.");
studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered students found.</p>';
return;
}
let tableHTML = `
<h4>Scores for: ${selectedQuizTitle}</h4>
<table>
<thead>
<tr>
<th>Student</th>
<th>Score (%)</th>
<th>Date Taken</th>
</tr>
</thead>
<tbody>
`;
let scoresFound = false;
// --- Iterate through each student username ---
studentUsernames.forEach(username => {
const studentData = registeredUsers[username];
console.log(`[DEBUG] Checking results for student: '${username}'`);
// Check if the student has a quizScores array
if (studentData && Array.isArray(studentData.quizScores)) {
// Find the result for the SPECIFICALLY selected quiz TITLE
const result = studentData.quizScores.find(score => score.quizName === selectedQuizTitle);
console.log(`[DEBUG] Result for quiz title '${selectedQuizTitle}' for student '${username}':`, result);
// Validate the result structure before using it
if (result && typeof result.score === 'number') {
scoresFound = true;
const scorePercentage = result.score; // Score is already stored as percentage
const dateTaken = result.timestamp ? new Date(result.timestamp).toLocaleString() : 'N/A';
console.log(`[DEBUG] Adding row for '${username}': Score=${scorePercentage}%, Date=${dateTaken}`);
tableHTML += `
<tr>
<td>${username}</td>
<td>${scorePercentage}%</td>
<td>${dateTaken}</td>
</tr>
`;
} else {
console.log(`[DEBUG] No valid result found for quiz title '${selectedQuizTitle}' for student '${username}' or result format is incorrect.`);
}
} else {
console.log(`[DEBUG] No quizScores array found for student '${username}'. Skipping.`);
}
}); // End of studentUsernames.forEach
if (!scoresFound) {
console.warn("[DEBUG] No scores found for any student for this specific quiz title:", selectedQuizTitle);
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;
console.log("[DEBUG] displayStudentScores finished.");
};
// --- Analytics Modal Functions ---
const openAnalyticsModal = () => {
populateTeacherAnalytics();
openModal(analyticsModal);
};
const closeAnalyticsModal = () => {
closeModal(analyticsModal);
};
const populateTeacherAnalytics = () => {
const lessons = getData(storageKeys.lessons);
const quizzes = getData(storageKeys.quizzes);
lessonCountSpan.textContent = lessons.length;
quizCountSpan.textContent = quizzes.length;
let totalPercentageSum = 0;
let totalQuizzesTakenCount = 0;
const registeredUsers = getUsers(); // Use function from login.js
const studentUsernames = Object.keys(registeredUsers).filter(username => registeredUsers[username]?.role === 'student');
studentUsernames.forEach(username => {
const studentData = registeredUsers[username];
if (studentData && Array.isArray(studentData.quizScores)) {
// Iterate through results for this student
studentData.quizScores.forEach(result => {
if (result && typeof result.score === 'number') { // Score is already percentage
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'; // Assuming homepage.html exists
}
function logout() {
sessionStorage.removeItem('loggedInUsername');
sessionStorage.removeItem('loggedInRole');
alert('You have been logged out.');
window.location.href = 'login.html'; // Redirect to login page
}
// --- Event Listeners ---
// Standard Modals Open/Close
createLessonBtn.addEventListener('click', () => { resetLessonForm(); openModal(lessonModal); });
createQuizBtn.addEventListener('click', () => { resetQuizForm(); addQuestion(); openModal(quizModal); }); // Add one question by default
deleteLessonBtn.addEventListener('click', () => {
deleteTypeSelect.value = "lesson"; // Set type
updateDeleteChoices(); // Populate choices for lessons
openModal(deleteModal);
});
deleteQuizBtn.addEventListener('click', () => {
deleteTypeSelect.value = "quiz"; // Set type
updateDeleteChoices(); // Populate choices for quizzes
openModal(deleteModal);
});
manageScoresBtn.addEventListener('click', () => {
populateQuizSelectForScores(); // Ensure dropdown is up-to-date
studentScoresDisplay.innerHTML='<p class="no-scores-message">Select a quiz to view student scores.</p>'; // Reset display
openModal(manageScoresModal);
});
closeButtons.forEach(button => {
button.addEventListener('click', () => {
const modalId = button.getAttribute('data-modal-id');
if (modalId) {
const modalToClose = document.getElementById(modalId);
if (modalToClose) closeModal(modalToClose);
}
});
});
// Close modal if clicking outside the content (but not on fullscreen modals)
window.addEventListener('click', (event) => {
if (event.target.classList.contains('modal') && !event.target.classList.contains('fullscreen')) {
closeModal(event.target);
}
});
// Form Submissions
lessonForm.addEventListener('submit', handleLessonFormSubmit);
quizForm.addEventListener('submit', handleQuizFormSubmit);
// Quiz Form - Add Question & Type Change
addQuestionBtn.addEventListener('click', () => addQuestion());
quizTypeSelect.addEventListener('change', toggleMultipleChoiceFields);
// Delete Modal - Type Change & Delete Button
deleteTypeSelect.addEventListener('change', updateDeleteChoices); // Update choices when type changes
deleteBtn.addEventListener('click', handleDelete);
// Manage Scores Modal - Quiz Selection Change
quizSelectForScores.addEventListener('change', displayStudentScores);
// Analytics Modal Open/Close/Navigation
analyticsBtn.addEventListener('click', openAnalyticsModal);
modalDashboardBtn.addEventListener('click', closeAnalyticsModal);
modalHomeBtn.addEventListener('click', goToHomepage);
modalLogoutBtn.addEventListener('click', logout);
// --- Initial Load ---
updateCreatedLessons();
updateCreatedQuizzes(); // Load existing quizzes on page load
});
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'teacher') {
alert('Access denied. Please log in as a teacher.');
window.location.href = 'login.html'; // Redirect to login if not a teacher
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const lessonModal = document.getElementById('lessonModal');
const quizModal = document.getElementById('quizModal');
const deleteModal = document.getElementById('deleteModal');
const manageScoresModal = document.getElementById('manageScoresModal');
const analyticsModal = document.getElementById('analyticsModal');
const createLessonBtn = document.getElementById('createLessonBtn');
const createQuizBtn = document.getElementById('createQuizBtn');
const deleteLessonBtn = document.getElementById('deleteLessonBtn');
const deleteQuizBtn = document.getElementById('deleteQuizBtn');
const manageScoresBtn = document.getElementById('manageScoresBtn');
const analyticsBtn = document.getElementById('analyticsBtn');
const closeButtons = document.querySelectorAll('.close');
// Lesson Form Elements
const lessonForm = document.getElementById('lessonForm');
const lessonModalTitle = document.getElementById('lessonModalTitle');
const editLessonIndexInput = document.getElementById('editLessonIndex');
const lessonTitleInput = document.getElementById('lessonTitle');
const lessonContentInput = document.getElementById('lessonContent');
const lessonSubmitBtn = document.getElementById('lessonSubmitBtn');
// Quiz Form Elements
const quizForm = document.getElementById('quizForm');
const quizModalTitle = document.getElementById('quizModalTitle');
const editQuizIndexInput = document.getElementById('editQuizIndex');
const quizTypeSelect = document.getElementById('quizType');
const quizTitleInput = document.getElementById('quizTitle');
const questionsContainer = document.getElementById('questionsContainer');
const addQuestionBtn = document.getElementById('addQuestionBtn');
const quizSubmitBtn = document.getElementById('quizSubmitBtn');
// Delete Modal Elements
const deleteTypeSelect = document.getElementById('deleteType');
const deleteChoiceSelect = document.getElementById('deleteChoice');
const deleteBtn = document.getElementById('deleteBtn');
// Manage Scores Modal Elements
const quizSelectForScores = document.getElementById('quizSelectForScores');
const studentScoresDisplay = document.getElementById('studentScoresDisplay');
// Analytics Modal Elements
const lessonCountSpan = document.getElementById('lessonCount');
const quizCountSpan = document.getElementById('quizCount');
const averageQuizScoreSpan = document.getElementById('averageQuizScore');
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// Display Areas
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
let questionCount = 0;
const storageKeys = {
lessons: 'createdLessons',
quizzes: 'createdQuizzes',
users: 'registeredUsers' // Key for all registered users (replaces studentResultPrefix)
};
// --- Utility Functions ---
const openModal = (modal) => {
modal.style.display = "block";
if (modal.classList.contains('fullscreen')) {
document.body.classList.add('modal-open');
}
};
const closeModal = (modal) => {
modal.style.display = "none";
if (modal.classList.contains('fullscreen')) {
document.body.classList.remove('modal-open');
}
// Reset forms/content on modal close
if (modal.id === 'lessonModal') resetLessonForm();
if (modal.id === 'quizModal') resetQuizForm();
if (modal.id === 'manageScoresModal') {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
quizSelectForScores.value = "";
}
if (modal.id === 'deleteModal') {
deleteTypeSelect.value = 'lesson';
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
}
};
// Gets array data (lessons, quizzes)
const getData = (key) => {
const data = localStorage.getItem(key);
if (data && data.startsWith('[')) {
try {
return JSON.parse(data);
} catch (e) {
console.error("Error parsing JSON array from localStorage for key:", key, e);
return [];
}
}
return [];
};
// Gets object data (registered users) - Reusing getUsers from login.js
// Ensure login.js is loaded first and getUsers is available globally
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.");
// Optionally disable functionality or redirect
return;
}
const setData = (key, data) => {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (e) {
console.error("Error setting data to localStorage for key:", key, e);
}
};
// --- Lesson Functions ---
const resetLessonForm = () => {
lessonForm.reset();
editLessonIndexInput.value = "-1";
lessonModalTitle.textContent = "Create Lesson";
lessonSubmitBtn.textContent = "Create Lesson";
};
const updateCreatedLessons = () => {
const lessons = getData(storageKeys.lessons);
createdLessonsDiv.innerHTML = '';
lessons.forEach((lesson, index) => {
const lessonDiv = document.createElement('div');
const contentDiv = document.createElement('div');
contentDiv.innerHTML = `<p><strong>${lesson.title}</strong></p><p>${lesson.content.substring(0, 100)}${lesson.content.length > 100 ? '...' : ''}</p>`;
lessonDiv.appendChild(contentDiv);
const editBtn = document.createElement('button');
editBtn.textContent = 'Edit';
editBtn.classList.add('btn', 'edit');
editBtn.dataset.index = index;
editBtn.addEventListener('click', () => editLesson(index));
lessonDiv.appendChild(editBtn);
createdLessonsDiv.appendChild(lessonDiv);
});
updateDeleteChoices(); // Update delete dropdown after lessons update
};
const editLesson = (index) => {
const lessons = getData(storageKeys.lessons);
if (index >= 0 && index < lessons.length) {
const lesson = lessons[index];
resetLessonForm();
editLessonIndexInput.value = index;
lessonTitleInput.value = lesson.title;
lessonContentInput.value = lesson.content;
lessonModalTitle.textContent = "Edit Lesson";
lessonSubmitBtn.textContent = "Save Changes";
openModal(lessonModal);
}
};
const handleLessonFormSubmit = (event) => {
event.preventDefault();
const lessonData = {
title: lessonTitleInput.value,
content: lessonContentInput.value,
};
const editIndex = parseInt(editLessonIndexInput.value, 10);
let lessons = getData(storageKeys.lessons);
if (editIndex > -1 && editIndex < lessons.length) {
lessons[editIndex] = lessonData;
alert('Lesson Updated!');
} else {
lessons.push(lessonData);
alert('Lesson Created!');
}
setData(storageKeys.lessons, lessons);
closeModal(lessonModal);
updateCreatedLessons();
};
// --- Quiz Functions ---
const resetQuizForm = () => {
quizForm.reset();
editQuizIndexInput.value = "-1";
questionsContainer.innerHTML = '';
questionCount = 0;
quizModalTitle.textContent = "Create Quiz";
quizSubmitBtn.textContent = "Create Quiz";
quizTypeSelect.disabled = false; // Re-enable type select
toggleMultipleChoiceFields(); // Ensure fields match default type
};
const toggleMultipleChoiceFields = () => {
const selectedType = quizTypeSelect.value;
const allQuestionContainers = questionsContainer.querySelectorAll('.question-container');
allQuestionContainers.forEach(qContainer => {
const mcContainer = qContainer.querySelector('.multiple-choice-container');
const choiceInputs = mcContainer ? mcContainer.querySelectorAll('input[type="text"]') : [];
const answerInput = qContainer.querySelector('input[name$="-correct-answer"]');
const answerLabel = answerInput ? answerInput.previousElementSibling : null;
if (mcContainer) {
mcContainer.style.display = selectedType === 'multiple-choice' ? 'block' : 'none';
// Set required only if multiple choice is selected
choiceInputs.forEach(input => input.required = (selectedType === 'multiple-choice'));
}
if (answerLabel && answerLabel.tagName === 'LABEL') {
answerLabel.textContent = selectedType === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):';
}
});
};
const addQuestion = (questionData = null) => {
const currentQIndex = questionData ? questionData.qIndex : ++questionCount;
const questionDiv = document.createElement('div');
questionDiv.classList.add('question-container');
questionDiv.dataset.qIndex = currentQIndex;
const qText = questionData ? questionData.questionText : '';
const qAnswer = questionData ? questionData.correctAnswer : '';
const qChoices = questionData ? questionData.choices : ['', '', '', '']; // Default empty choices
questionDiv.innerHTML = `
<h4>Question ${currentQIndex}</h4>
<label for="question-${currentQIndex}">Question Text:</label>
<input type="text" id="question-${currentQIndex}" name="question-${currentQIndex}" value="${qText}" required><br>
<div class="multiple-choice-container" style="display: ${quizTypeSelect.value === 'multiple-choice' ? 'block' : 'none'};">
<label>Choices:</label><br>
<input type="text" name="question-${currentQIndex}-choice-1" placeholder="Choice 1" value="${qChoices[0] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-2" placeholder="Choice 2" value="${qChoices[1] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-3" placeholder="Choice 3" value="${qChoices[2] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
<input type="text" name="question-${currentQIndex}-choice-4" placeholder="Choice 4" value="${qChoices[3] || ''}" ${quizTypeSelect.value === 'multiple-choice' ? 'required' : ''}><br>
</div>
<label for="question-${currentQIndex}-correct-answer">${quizTypeSelect.value === 'identification' ? 'Correct Answer:' : 'Correct Answer (must match one choice):'}</label>
<input type="text" name="question-${currentQIndex}-correct-answer" value="${qAnswer}" required><br>
`;
questionsContainer.appendChild(questionDiv);
if (!questionData) questionCount = currentQIndex; // Update global count only for new questions
// No need to call toggleMultipleChoiceFields here as it's called on type change and form reset
};
const updateCreatedQuizzes = () => {
const quizzes = getData(storageKeys.quizzes);
createdQuizzesDiv.innerHTML = '';
quizzes.forEach((quiz, index) => {
const quizDiv = document.createElement('div');
const contentDiv = document.createElement('div');
// Basic validation before displaying
const title = quiz.quizTitle || 'Untitled Quiz';
const type = quiz.quizType || 'N/A';
const numQuestions = Array.isArray(quiz.questions) ? quiz.questions.length : 0;
contentDiv.innerHTML = `<p><strong>${title}</strong></p><p>(Type: ${type}, Questions: ${numQuestions})</p>`;
quizDiv.appendChild(contentDiv);
// No Edit button for quizzes currently
createdQuizzesDiv.appendChild(quizDiv);
});
updateDeleteChoices(); // Update delete dropdown after quizzes update
populateQuizSelectForScores(); // Update scores dropdown after quizzes update
};
// Edit Quiz function remains but is not called from UI
const editQuiz = (index) => {
const quizzes = getData(storageKeys.quizzes);
if (index >= 0 && index < quizzes.length) {
const quiz = quizzes[index];
resetQuizForm();
editQuizIndexInput.value = index;
quizTitleInput.value = quiz.quizTitle;
quizTypeSelect.value = quiz.quizType;
quizTypeSelect.disabled = true; // Disable type change when editing
questionCount = 0; // Reset count for adding existing questions
quiz.questions.forEach((q, qIndex) => {
addQuestion({ ...q, qIndex: qIndex + 1 }); // Pass existing data
});
quizModalTitle.textContent = "Edit Quiz";
quizSubmitBtn.textContent = "Save Changes";
openModal(quizModal);
toggleMultipleChoiceFields(); // Ensure fields match loaded quiz type
}
};
const handleQuizFormSubmit = (event) => {
event.preventDefault();
const editIndex = parseInt(editQuizIndexInput.value, 10);
const quizType = quizTypeSelect.value;
const quizTitle = quizTitleInput.value;
const questions = [];
const questionElements = questionsContainer.querySelectorAll('.question-container');
const currentQuestionCount = questionElements.length; // Use actual number of question divs
for (let i = 0; i < currentQuestionCount; i++) {
const qContainer = questionElements[i];
const qIndex = qContainer.dataset.qIndex; // Get index from data attribute
const questionText = qContainer.querySelector(`[name='question-${qIndex}']`)?.value.trim();
const correctAnswer = qContainer.querySelector(`[name='question-${qIndex}-correct-answer']`)?.value.trim();
const choices = [];
if (!questionText || correctAnswer === undefined || correctAnswer === null || correctAnswer === "") {
alert(`Please fill out question text and correct answer for Question ${qIndex}.`);
return;
}
if (quizType === 'multiple-choice') {
const choiceInputs = qContainer.querySelectorAll(`.multiple-choice-container input[type="text"]`);
let choicesComplete = true;
choiceInputs.forEach(input => {
const choiceValue = input.value.trim();
if (!choiceValue) choicesComplete = false;
choices.push(choiceValue);
});
if (!choicesComplete) {
alert(`Please fill out all choices for Question ${qIndex}.`);
return;
}
// Ensure the correct answer is one of the choices provided
if (!choices.includes(correctAnswer)) {
alert(`The correct answer for Question ${qIndex} ("${correctAnswer}") must exactly match one of the provided choices.`);
return;
}
}
questions.push({ questionText, choices: quizType === 'multiple-choice' ? choices : [], correctAnswer });
}
if (questions.length === 0) {
alert('Please add at least one question to the quiz.');
return;
}
const quizData = { quizType, quizTitle, questions };
let quizzes = getData(storageKeys.quizzes);
if (editIndex > -1 && editIndex < quizzes.length) {
quizzes[editIndex] = quizData;
alert('Quiz Updated!');
} else {
quizzes.push(quizData);
alert('Quiz Created!');
}
setData(storageKeys.quizzes, quizzes);
closeModal(quizModal);
updateCreatedQuizzes();
};
// --- Delete Functions (Handles both Lessons and Quizzes) ---
const updateDeleteChoices = () => {
const deleteType = deleteTypeSelect.value; // Read the selected type
deleteChoiceSelect.innerHTML = '<option value="">-- Select --</option>';
const items = getData(deleteType === "lesson" ? storageKeys.lessons : storageKeys.quizzes);
items.forEach((item, index) => {
const option = document.createElement('option');
option.value = index;
// Use 'title' for lessons and 'quizTitle' for quizzes, provide fallback
option.textContent = item.title || item.quizTitle || `${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} ${index + 1}`;
deleteChoiceSelect.appendChild(option);
});
deleteBtn.disabled = items.length === 0; // Disable button if no items
};
const handleDelete = () => {
const selectedIndex = deleteChoiceSelect.value;
const deleteType = deleteTypeSelect.value; // Get the type from the dropdown
if (selectedIndex === "") {
alert('Please select an item to delete.');
return;
}
const storageKey = deleteType === 'lesson' ? storageKeys.lessons : storageKeys.quizzes;
let items = getData(storageKey);
const itemToDelete = items[selectedIndex];
const itemName = itemToDelete?.title || itemToDelete?.quizTitle || `${deleteType} ${parseInt(selectedIndex)+1}`;
if (confirm(`Are you sure you want to delete ${deleteType} "${itemName}"? This cannot be undone.`)) {
items.splice(selectedIndex, 1);
setData(storageKey, items);
alert(`${deleteType.charAt(0).toUpperCase() + deleteType.slice(1)} Deleted!`);
// Update the correct display area
if (deleteType === 'lesson') {
updateCreatedLessons();
} else {
updateCreatedQuizzes(); // This also updates score/delete dropdowns
}
closeModal(deleteModal); // Close and reset the modal
}
};
// --- Manage Scores Functions ---
const populateQuizSelectForScores = () => {
const quizzes = getData(storageKeys.quizzes);
quizSelectForScores.innerHTML = '<option value="">-- Select a Quiz --</option>';
quizzes.forEach((quiz, index) => {
const option = document.createElement('option');
option.value = index; // Use the index as the value
option.textContent = quiz.quizTitle || `Quiz ${index + 1}`; // Fallback title
quizSelectForScores.appendChild(option);
});
};
const displayStudentScores = () => {
const selectedQuizIndex = quizSelectForScores.value;
studentScoresDisplay.innerHTML = ''; // Clear previous content
console.log(`[DEBUG] displayStudentScores called. Selected Quiz Index: '${selectedQuizIndex}'`);
if (selectedQuizIndex === "") {
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Select a quiz to view student scores.</p>';
console.log("[DEBUG] No quiz selected. Aborting.");
return;
}
const quizzes = getData(storageKeys.quizzes);
const selectedQuiz = quizzes[selectedQuizIndex];
if (!selectedQuiz || !selectedQuiz.quizTitle) {
console.error(`[DEBUG] Error: Could not find valid quiz data or title for index ${selectedQuizIndex}`);
studentScoresDisplay.innerHTML = '<p class="no-scores-message">Error: Could not find selected quiz data.</p>';
return;
}
const selectedQuizTitle = selectedQuiz.quizTitle;
console.log("[DEBUG] Selected Quiz Data:", selectedQuiz);
// --- Get ALL registered users ---
const registeredUsers = getUsers(); // Use function from login.js
console.log("[DEBUG] Raw Registered Users Data from getUsers():", registeredUsers);
if (Object.keys(registeredUsers).length === 0) {
console.warn("[DEBUG] No registered users found.");
studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered users found.</p>';
return;
}
// --- Filter for users with role 'student' ---
const studentUsernames = Object.keys(registeredUsers).filter(username => {
const user = registeredUsers[username];
const isStudent = user && user.role === 'student';
if (!isStudent) {
console.log(`[DEBUG] Filtering out user '${username}'. Role is not 'student' or user data is malformed. User data:`, user);
}
return isStudent;
});
console.log("[DEBUG] Filtered Student Usernames:", studentUsernames);
if (studentUsernames.length === 0) {
console.warn("[DEBUG] No users with role 'student' found after filtering.");
studentScoresDisplay.innerHTML = '<p class="no-scores-message">No registered students found.</p>';
return;
}
let tableHTML = `
<h4>Scores for: ${selectedQuizTitle}</h4>
<table>
<thead>
<tr>
<th>Student</th>
<th>Score (%)</th>
<th>Date Taken</th>
</tr>
</thead>
<tbody>
`;
let scoresFound = false;
// --- Iterate through each student username ---
studentUsernames.forEach(username => {
const studentData = registeredUsers[username];
console.log(`[DEBUG] Checking results for student: '${username}'`);
// Check if the student has a quizScores array
if (studentData && Array.isArray(studentData.quizScores)) {
// Find the result for the SPECIFICALLY selected quiz TITLE
const result = studentData.quizScores.find(score => score.quizName === selectedQuizTitle);
console.log(`[DEBUG] Result for quiz title '${selectedQuizTitle}' for student '${username}':`, result);
// Validate the result structure before using it
if (result && typeof result.score === 'number') {
scoresFound = true;
const scorePercentage = result.score; // Score is already stored as percentage
const dateTaken = result.timestamp ? new Date(result.timestamp).toLocaleString() : 'N/A';
console.log(`[DEBUG] Adding row for '${username}': Score=${scorePercentage}%, Date=${dateTaken}`);
tableHTML += `
<tr>
<td>${username}</td>
<td>${scorePercentage}%</td>
<td>${dateTaken}</td>
</tr>
`;
} else {
console.log(`[DEBUG] No valid result found for quiz title '${selectedQuizTitle}' for student '${username}' or result format is incorrect.`);
}
} else {
console.log(`[DEBUG] No quizScores array found for student '${username}'. Skipping.`);
}
}); // End of studentUsernames.forEach
if (!scoresFound) {
console.warn("[DEBUG] No scores found for any student for this specific quiz title:", selectedQuizTitle);
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;
console.log("[DEBUG] displayStudentScores finished.");
};
// --- Analytics Modal Functions ---
const openAnalyticsModal = () => {
populateTeacherAnalytics();
openModal(analyticsModal);
};
const closeAnalyticsModal = () => {
closeModal(analyticsModal);
};
const populateTeacherAnalytics = () => {
const lessons = getData(storageKeys.lessons);
const quizzes = getData(storageKeys.quizzes);
lessonCountSpan.textContent = lessons.length;
quizCountSpan.textContent = quizzes.length;
let totalPercentageSum = 0;
let totalQuizzesTakenCount = 0;
const registeredUsers = getUsers(); // Use function from login.js
const studentUsernames = Object.keys(registeredUsers).filter(username => registeredUsers[username]?.role === 'student');
studentUsernames.forEach(username => {
const studentData = registeredUsers[username];
if (studentData && Array.isArray(studentData.quizScores)) {
// Iterate through results for this student
studentData.quizScores.forEach(result => {
if (result && typeof result.score === 'number') { // Score is already percentage
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'; // Assuming homepage.html exists
}
function logout() {
sessionStorage.removeItem('loggedInUsername');
sessionStorage.removeItem('loggedInRole');
alert('You have been logged out.');
window.location.href = 'login.html'; // Redirect to login page
}
// --- Event Listeners ---
// Standard Modals Open/Close
createLessonBtn.addEventListener('click', () => { resetLessonForm(); openModal(lessonModal); });
createQuizBtn.addEventListener('click', () => { resetQuizForm(); addQuestion(); openModal(quizModal); }); // Add one question by default
deleteLessonBtn.addEventListener('click', () => {
deleteTypeSelect.value = "lesson"; // Set type
updateDeleteChoices(); // Populate choices for lessons
openModal(deleteModal);
});
deleteQuizBtn.addEventListener('click', () => {
deleteTypeSelect.value = "quiz"; // Set type
updateDeleteChoices(); // Populate choices for quizzes
openModal(deleteModal);
});
manageScoresBtn.addEventListener('click', () => {
populateQuizSelectForScores(); // Ensure dropdown is up-to-date
studentScoresDisplay.innerHTML='<p class="no-scores-message">Select a quiz to view student scores.</p>'; // Reset display
openModal(manageScoresModal);
});
closeButtons.forEach(button => {
button.addEventListener('click', () => {
const modalId = button.getAttribute('data-modal-id');
if (modalId) {
const modalToClose = document.getElementById(modalId);
if (modalToClose) closeModal(modalToClose);
}
});
});
// Close modal if clicking outside the content (but not on fullscreen modals)
window.addEventListener('click', (event) => {
if (event.target.classList.contains('modal') && !event.target.classList.contains('fullscreen')) {
closeModal(event.target);
}
});
// Form Submissions
lessonForm.addEventListener('submit', handleLessonFormSubmit);
quizForm.addEventListener('submit', handleQuizFormSubmit);
// Quiz Form - Add Question & Type Change
addQuestionBtn.addEventListener('click', () => addQuestion());
quizTypeSelect.addEventListener('change', toggleMultipleChoiceFields);
// Delete Modal - Type Change & Delete Button
deleteTypeSelect.addEventListener('change', updateDeleteChoices); // Update choices when type changes
deleteBtn.addEventListener('click', handleDelete);
// Manage Scores Modal - Quiz Selection Change
quizSelectForScores.addEventListener('change', displayStudentScores);
// Analytics Modal Open/Close/Navigation
analyticsBtn.addEventListener('click', openAnalyticsModal);
modalDashboardBtn.addEventListener('click', closeAnalyticsModal);
modalHomeBtn.addEventListener('click', goToHomepage);
modalLogoutBtn.addEventListener('click', logout);
// --- Initial Load ---
updateCreatedLessons();
updateCreatedQuizzes(); // Load existing quizzes on page load
});
<div class="container">
<h1>Student Dashboard</h1>
<!-- Quiz Completion Status Message -->
<div id="quiz-completion-status" class="completion-notice hidden">
<p>Please complete all available quizzes to view your performance analytics.</p>
</div>
<!-- Display Created Lessons -->
<section id="lessons-section">
<h2>Available Lessons</h2>
<!-- Container for lessons where event listener will be attached -->
<div id="createdLessons">
<p>Loading lessons...</p>
</div>
</section>
<!-- Display Created Quizzes -->
<section id="quizzes-section">
<h2>Available Quizzes</h2>
<!-- Container for quizzes where event listener will be attached -->
<div id="createdQuizzes">
<p>Loading quizzes...</p>
</div>
</section>
</div>
<!-- Performance Analytics Button -->
<button id="analyticsBtn" class="analytics-btn" disabled>View Performance & Analytics</button>
<!-- Performance Analytics Modal -->
<div id="analyticsModal" class="modal"> <!-- Removed fullscreen class -->
<div class="modal-content">
<!-- Close Button Removed -->
<h2>Performance & Analytics</h2>
<div class="analytics-section">
<h3>Activity</h3>
<p><strong>Last Accessed:</strong> <span id="lastAccessed">N/A</span></p>
</div>
<div class="analytics-section">
<h3>Lesson Progress</h3>
<ul id="lessonProgressList">
<li>Loading lesson status...</li>
</ul>
</div>
<div class="analytics-section">
<h3>Quiz Scores</h3>
<ul id="quizScoresList">
<li>No quizzes taken yet.</li>
</ul>
</div>
<div class="analytics-section">
<h3>Overall Grade</h3>
<p><strong id="overallGrade">N/A</strong></p>
</div>
<!-- Navigation Buttons Inside Modal -->
<div class="modal-navigation">
<button id="modalDashboardBtn" class="modal-nav-btn dashboard">Back to Dashboard</button>
<button id="modalHomeBtn" class="modal-nav-btn home">Homepage</button>
<button id="modalLogoutBtn" class="modal-nav-btn logout">Logout</button>
</div>
</div>
</div>
<script src="login.js"></script> <!-- Include for getUsers/saveUsers -->
<script src="student.js"></script>
</body>
</html>
<div class="container">
<h1>Student Dashboard</h1>
<!-- Quiz Completion Status Message -->
<div id="quiz-completion-status" class="completion-notice hidden">
<p>Please complete all available quizzes to view your performance analytics.</p>
</div>
<!-- Display Created Lessons -->
<section id="lessons-section">
<h2>Available Lessons</h2>
<!-- Container for lessons where event listener will be attached -->
<div id="createdLessons">
<p>Loading lessons...</p>
</div>
</section>
<!-- Display Created Quizzes -->
<section id="quizzes-section">
<h2>Available Quizzes</h2>
<!-- Container for quizzes where event listener will be attached -->
<div id="createdQuizzes">
<p>Loading quizzes...</p>
</div>
</section>
</div>
<!-- Performance Analytics Button -->
<button id="analyticsBtn" class="analytics-btn" disabled>View Performance & Analytics</button>
<!-- Performance Analytics Modal -->
<div id="analyticsModal" class="modal"> <!-- Removed fullscreen class -->
<div class="modal-content">
<!-- Close Button Removed -->
<h2>Performance & Analytics</h2>
<div class="analytics-section">
<h3>Activity</h3>
<p><strong>Last Accessed:</strong> <span id="lastAccessed">N/A</span></p>
</div>
<div class="analytics-section">
<h3>Lesson Progress</h3>
<ul id="lessonProgressList">
<li>Loading lesson status...</li>
</ul>
</div>
<div class="analytics-section">
<h3>Quiz Scores</h3>
<ul id="quizScoresList">
<li>No quizzes taken yet.</li>
</ul>
</div>
<div class="analytics-section">
<h3>Overall Grade</h3>
<p><strong id="overallGrade">N/A</strong></p>
</div>
<!-- Navigation Buttons Inside Modal -->
<div class="modal-navigation">
<button id="modalDashboardBtn" class="modal-nav-btn dashboard">Back to Dashboard</button>
<button id="modalHomeBtn" class="modal-nav-btn home">Homepage</button>
<button id="modalLogoutBtn" class="modal-nav-btn logout">Logout</button>
</div>
</div>
</div>
<script src="login.js"></script> <!-- Include for getUsers/saveUsers -->
<script src="student.js"></script>
</body>
</html>
/* Existing styles below... */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 20px 20px 80px 20px; /* Re-added top padding, kept side/bottom */
line-height: 1.6;
}
/* Prevent body scroll when modal is open */
body.modal-open {
overflow: hidden;
}
.container {
max-width: 900px;
margin: 20px auto;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
h1, h2, h3, h4 {
color: #333;
}
h1 {
text-align: center;
color: #4CAF50;
margin-bottom: 30px;
}
h2 {
border-bottom: 2px solid #4CAF50;
padding-bottom: 5px;
margin-top: 30px;
}
section {
margin-bottom: 30px;
}
/* Quiz Completion Notice */
.completion-notice {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffeeba;
padding: 15px;
margin-bottom: 20px;
border-radius: 5px;
text-align: center;
}
.completion-notice p {
margin: 0;
font-weight: bold;
}
.lesson, .quiz {
border: 1px solid #ddd;
background-color: #f9f9f9;
padding: 15px;
margin-bottom: 15px;
border-radius: 5px;
position: relative; /* Needed for absolute positioning of button if desired */
}
.lesson h4, .quiz h4 {
margin-top: 0;
color: #555;
}
/* Lesson Read Button */
.mark-read-btn {
padding: 6px 12px;
background-color: #17a2b8; /* Teal */
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-top: 10px;
transition: background-color 0.3s ease, opacity 0.3s ease;
display: inline-block; /* Or block if needed */
}
.mark-read-btn:hover:not(:disabled) {
background-color: #138496;
}
.mark-read-btn:disabled {
background-color: #a6d8de; /* Lighter teal */
cursor: not-allowed;
opacity: 0.7;
}
.btn {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-top: 10px;
transition: background-color 0.3s ease;
}
.btn:hover:not(:disabled) { /* Ensure hover only applies when not disabled */
background-color: #45a049;
}
.btn:disabled {
background-color: #ccc;
cursor: not-allowed;
opacity: 0.6; /* Slightly adjust opacity */
}
.submit-quiz-btn {
background-color: #007bff;
}
.submit-quiz-btn:hover:not(:disabled) {
background-color: #0056b3;
}
.quiz-question {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #eee;
}
.quiz-question p strong {
display: inline-block; /* Allow span to sit next to it */
margin-bottom: 10px;
}
/* Answer Input Styling */
.quiz-question input[type="text"] {
width: calc(100% - 22px);
padding: 10px;
margin-top: 5px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.quiz-question .choices label {
display: block;
margin-bottom: 8px;
cursor: pointer;
padding: 8px;
border-radius: 4px;
background-color: #e9e9e9;
transition: background-color 0.2s ease;
}
.quiz-question .choices label:hover {
background-color: #dcdcdc;
}
.quiz-question .choices input[type="radio"] {
margin-right: 10px;
vertical-align: middle;
}
/* Score Display */
.quiz-score-area {
margin-top: 20px;
padding: 15px;
background-color: #e3f2fd;
border: 1px solid #bbdefb;
border-radius: 5px;
text-align: center;
}
.quiz-score-area h3 {
margin: 0;
color: #0d47a1;
}
/* Hide elements */
.hidden {
display: none;
}
/* --- Feedback Styles --- */
.feedback-mark { /* Container for the mark */
display: inline-block; /* Allows margin */
margin-left: 8px;
font-size: 1.2em;
font-weight: bold;
vertical-align: middle; /* Align with text */
}
.correct-mark {
color: green;
}
.incorrect-mark {
color: red;
}
.correct-answer-highlight {
background-color: #c8e6c9 !important;
border: 1px solid #a5d6a7;
font-weight: bold;
}
.correct-answer-text {
display: block;
margin-top: 5px;
color: #2e7d32;
font-style: italic;
font-size: 0.9em;
}
.incorrect-answer-input {
border-color: #e57373 !important;
background-color: #ffebee;
}
.incorrect-choice-selected {
background-color: #ffcdd2 !important;
border: 1px solid #ef9a9a;
text-decoration: line-through;
}
.quiz-question .choices label.correct-answer-highlight,
.quiz-question .choices label.incorrect-choice-selected {
opacity: 1;
color: #333;
}
/* --- Analytics Button Style --- */
.analytics-btn {
position: fixed;
bottom: 20px;
right: 20px;
padding: 12px 25px;
background-color: #6f42c1; /* Purple color */
color: white;
border: none;
border-radius: 25px; /* Pill shape */
cursor: pointer;
font-size: 15px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 1000; /* Ensure it's above other content */
transition: background-color 0.3s ease, transform 0.2s ease, opacity 0.3s ease;
}
.analytics-btn:hover:not(:disabled) {
background-color: #5a379b;
transform: translateY(-2px); /* Slight lift on hover */
}
.analytics-btn:disabled {
background-color: #b3a1d1; /* Lighter purple when disabled */
cursor: not-allowed;
opacity: 0.7;
transform: none;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* --- Fullscreen Modal Styles --- */
.modal {
display: none; /* Hidden by default */
position: fixed;
z-index: 1001; /* Above the button */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: hidden; /* Prevent body scroll when modal is open */
background-color: #fefefe; /* Use solid background instead of overlay */
}
.modal-content {
background-color: transparent; /* Make content background transparent */
margin: 0; /* Remove margin */
padding: 30px; /* Adjust padding for fullscreen */
border: none; /* Remove border */
width: 100%; /* Full width */
height: 100%; /* Full height */
max-width: none; /* Remove max-width */
border-radius: 0; /* Remove border-radius */
box-shadow: none; /* Remove box-shadow */
position: relative;
overflow-y: auto; /* Allow content scrolling */
box-sizing: border-box; /* Include padding in height/width */
}
/* Close Button Styles Removed */
/* .close-btn { ... } */
.modal h2 {
text-align: center;
color: #6f42c1;
margin-top: 10px; /* Add some top margin */
margin-bottom: 30px; /* Increase bottom margin */
font-size: 1.8em; /* Larger title */
}
.analytics-section {
margin-bottom: 25px; /* Increase spacing */
padding-bottom: 20px;
border-bottom: 1px solid #eee;
max-width: 800px; /* Limit width of content sections */
margin-left: auto; /* Center content sections */
margin-right: auto;
}
.analytics-section:last-of-type { /* Remove border from last section before nav */
border-bottom: none;
}
.analytics-section h3 {
color: #444;
margin-bottom: 15px;
font-size: 1.3em; /* Larger section titles */
}
#quizScoresList, #lessonProgressList { /* Apply to both lists */
list-style: none;
padding: 0;
max-height: 30vh; /* Adjust max height relative to viewport */
overflow-y: auto;
}
#quizScoresList li, #lessonProgressList li { /* Apply to both lists */
background-color: #f9f9f9;
padding: 10px 15px; /* Increase padding */
margin-bottom: 8px; /* Increase spacing */
border-radius: 4px;
border: 1px solid #eee;
font-size: 1em; /* Slightly larger font */
display: flex; /* Use flex for alignment */
justify-content: space-between; /* Space out title and status/score */
align-items: center;
}
#quizScoresList li strong, #lessonProgressList li strong { /* Apply to both lists */
color: #333;
margin-right: 10px; /* Add space between title and value */
}
/* Lesson Progress Specific Styles in Modal */
#lessonProgressList .status-completed,
#lessonProgressList .status-read { color: green; font-weight: bold; }
#lessonProgressList .status-not-started { color: grey; }
#overallGrade {
font-size: 1.4em; /* Larger grade font */
font-weight: bold;
color: #28a745;
}
/* Styles for Navigation Buttons inside Modal */
.modal-navigation {
margin-top: 30px; /* Increase space */
padding-top: 25px;
border-top: 1px solid #ccc; /* Slightly darker border */
text-align: center;
display: flex;
justify-content: center;
gap: 20px; /* Increase gap */
max-width: 800px; /* Limit width */
margin-left: auto;
margin-right: auto;
}
.modal-nav-btn {
padding: 12px 25px; /* Larger buttons */
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em; /* Larger font */
font-weight: bold;
transition: background-color 0.3s ease, transform 0.2s ease;
}
.modal-nav-btn.dashboard { /* Style for the new dashboard button */
background-color: #ffc107; /* Yellow/Orange color */
color: #333;
}
.modal-nav-btn.dashboard:hover {
background-color: #e0a800;
transform: translateY(-1px);
}
.modal-nav-btn.home {
background-color: #17a2b8;
color: white;
}
.modal-nav-btn.home:hover {
background-color: #138496;
transform: translateY(-1px);
}
.modal-nav-btn.logout {
background-color: #dc3545;
color: white;
}
.modal-nav-btn.logout:hover {
background-color: #c82333;
transform: translateY(-1px);
}
/* Existing styles below... */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 20px 20px 80px 20px; /* Re-added top padding, kept side/bottom */
line-height: 1.6;
}
/* Prevent body scroll when modal is open */
body.modal-open {
overflow: hidden;
}
.container {
max-width: 900px;
margin: 20px auto;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
h1, h2, h3, h4 {
color: #333;
}
h1 {
text-align: center;
color: #4CAF50;
margin-bottom: 30px;
}
h2 {
border-bottom: 2px solid #4CAF50;
padding-bottom: 5px;
margin-top: 30px;
}
section {
margin-bottom: 30px;
}
/* Quiz Completion Notice */
.completion-notice {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffeeba;
padding: 15px;
margin-bottom: 20px;
border-radius: 5px;
text-align: center;
}
.completion-notice p {
margin: 0;
font-weight: bold;
}
.lesson, .quiz {
border: 1px solid #ddd;
background-color: #f9f9f9;
padding: 15px;
margin-bottom: 15px;
border-radius: 5px;
position: relative; /* Needed for absolute positioning of button if desired */
}
.lesson h4, .quiz h4 {
margin-top: 0;
color: #555;
}
/* Lesson Read Button */
.mark-read-btn {
padding: 6px 12px;
background-color: #17a2b8; /* Teal */
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-top: 10px;
transition: background-color 0.3s ease, opacity 0.3s ease;
display: inline-block; /* Or block if needed */
}
.mark-read-btn:hover:not(:disabled) {
background-color: #138496;
}
.mark-read-btn:disabled {
background-color: #a6d8de; /* Lighter teal */
cursor: not-allowed;
opacity: 0.7;
}
.btn {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-top: 10px;
transition: background-color 0.3s ease;
}
.btn:hover:not(:disabled) { /* Ensure hover only applies when not disabled */
background-color: #45a049;
}
.btn:disabled {
background-color: #ccc;
cursor: not-allowed;
opacity: 0.6; /* Slightly adjust opacity */
}
.submit-quiz-btn {
background-color: #007bff;
}
.submit-quiz-btn:hover:not(:disabled) {
background-color: #0056b3;
}
.quiz-question {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #eee;
}
.quiz-question p strong {
display: inline-block; /* Allow span to sit next to it */
margin-bottom: 10px;
}
/* Answer Input Styling */
.quiz-question input[type="text"] {
width: calc(100% - 22px);
padding: 10px;
margin-top: 5px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.quiz-question .choices label {
display: block;
margin-bottom: 8px;
cursor: pointer;
padding: 8px;
border-radius: 4px;
background-color: #e9e9e9;
transition: background-color 0.2s ease;
}
.quiz-question .choices label:hover {
background-color: #dcdcdc;
}
.quiz-question .choices input[type="radio"] {
margin-right: 10px;
vertical-align: middle;
}
/* Score Display */
.quiz-score-area {
margin-top: 20px;
padding: 15px;
background-color: #e3f2fd;
border: 1px solid #bbdefb;
border-radius: 5px;
text-align: center;
}
.quiz-score-area h3 {
margin: 0;
color: #0d47a1;
}
/* Hide elements */
.hidden {
display: none;
}
/* --- Feedback Styles --- */
.feedback-mark { /* Container for the mark */
display: inline-block; /* Allows margin */
margin-left: 8px;
font-size: 1.2em;
font-weight: bold;
vertical-align: middle; /* Align with text */
}
.correct-mark {
color: green;
}
.incorrect-mark {
color: red;
}
.correct-answer-highlight {
background-color: #c8e6c9 !important;
border: 1px solid #a5d6a7;
font-weight: bold;
}
.correct-answer-text {
display: block;
margin-top: 5px;
color: #2e7d32;
font-style: italic;
font-size: 0.9em;
}
.incorrect-answer-input {
border-color: #e57373 !important;
background-color: #ffebee;
}
.incorrect-choice-selected {
background-color: #ffcdd2 !important;
border: 1px solid #ef9a9a;
text-decoration: line-through;
}
.quiz-question .choices label.correct-answer-highlight,
.quiz-question .choices label.incorrect-choice-selected {
opacity: 1;
color: #333;
}
/* --- Analytics Button Style --- */
.analytics-btn {
position: fixed;
bottom: 20px;
right: 20px;
padding: 12px 25px;
background-color: #6f42c1; /* Purple color */
color: white;
border: none;
border-radius: 25px; /* Pill shape */
cursor: pointer;
font-size: 15px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 1000; /* Ensure it's above other content */
transition: background-color 0.3s ease, transform 0.2s ease, opacity 0.3s ease;
}
.analytics-btn:hover:not(:disabled) {
background-color: #5a379b;
transform: translateY(-2px); /* Slight lift on hover */
}
.analytics-btn:disabled {
background-color: #b3a1d1; /* Lighter purple when disabled */
cursor: not-allowed;
opacity: 0.7;
transform: none;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* --- Fullscreen Modal Styles --- */
.modal {
display: none; /* Hidden by default */
position: fixed;
z-index: 1001; /* Above the button */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: hidden; /* Prevent body scroll when modal is open */
background-color: #fefefe; /* Use solid background instead of overlay */
}
.modal-content {
background-color: transparent; /* Make content background transparent */
margin: 0; /* Remove margin */
padding: 30px; /* Adjust padding for fullscreen */
border: none; /* Remove border */
width: 100%; /* Full width */
height: 100%; /* Full height */
max-width: none; /* Remove max-width */
border-radius: 0; /* Remove border-radius */
box-shadow: none; /* Remove box-shadow */
position: relative;
overflow-y: auto; /* Allow content scrolling */
box-sizing: border-box; /* Include padding in height/width */
}
/* Close Button Styles Removed */
/* .close-btn { ... } */
.modal h2 {
text-align: center;
color: #6f42c1;
margin-top: 10px; /* Add some top margin */
margin-bottom: 30px; /* Increase bottom margin */
font-size: 1.8em; /* Larger title */
}
.analytics-section {
margin-bottom: 25px; /* Increase spacing */
padding-bottom: 20px;
border-bottom: 1px solid #eee;
max-width: 800px; /* Limit width of content sections */
margin-left: auto; /* Center content sections */
margin-right: auto;
}
.analytics-section:last-of-type { /* Remove border from last section before nav */
border-bottom: none;
}
.analytics-section h3 {
color: #444;
margin-bottom: 15px;
font-size: 1.3em; /* Larger section titles */
}
#quizScoresList, #lessonProgressList { /* Apply to both lists */
list-style: none;
padding: 0;
max-height: 30vh; /* Adjust max height relative to viewport */
overflow-y: auto;
}
#quizScoresList li, #lessonProgressList li { /* Apply to both lists */
background-color: #f9f9f9;
padding: 10px 15px; /* Increase padding */
margin-bottom: 8px; /* Increase spacing */
border-radius: 4px;
border: 1px solid #eee;
font-size: 1em; /* Slightly larger font */
display: flex; /* Use flex for alignment */
justify-content: space-between; /* Space out title and status/score */
align-items: center;
}
#quizScoresList li strong, #lessonProgressList li strong { /* Apply to both lists */
color: #333;
margin-right: 10px; /* Add space between title and value */
}
/* Lesson Progress Specific Styles in Modal */
#lessonProgressList .status-completed,
#lessonProgressList .status-read { color: green; font-weight: bold; }
#lessonProgressList .status-not-started { color: grey; }
#overallGrade {
font-size: 1.4em; /* Larger grade font */
font-weight: bold;
color: #28a745;
}
/* Styles for Navigation Buttons inside Modal */
.modal-navigation {
margin-top: 30px; /* Increase space */
padding-top: 25px;
border-top: 1px solid #ccc; /* Slightly darker border */
text-align: center;
display: flex;
justify-content: center;
gap: 20px; /* Increase gap */
max-width: 800px; /* Limit width */
margin-left: auto;
margin-right: auto;
}
.modal-nav-btn {
padding: 12px 25px; /* Larger buttons */
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em; /* Larger font */
font-weight: bold;
transition: background-color 0.3s ease, transform 0.2s ease;
}
.modal-nav-btn.dashboard { /* Style for the new dashboard button */
background-color: #ffc107; /* Yellow/Orange color */
color: #333;
}
.modal-nav-btn.dashboard:hover {
background-color: #e0a800;
transform: translateY(-1px);
}
.modal-nav-btn.home {
background-color: #17a2b8;
color: white;
}
.modal-nav-btn.home:hover {
background-color: #138496;
transform: translateY(-1px);
}
.modal-nav-btn.logout {
background-color: #dc3545;
color: white;
}
.modal-nav-btn.logout:hover {
background-color: #c82333;
transform: translateY(-1px);
}
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'student') {
alert('Access denied. Please log in as a student.');
// Ensure login.js is loaded if redirecting to index.html which might be the login page
window.location.href = 'login.html'; // Redirect if not a student
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
const quizCompletionStatusDiv = document.getElementById('quiz-completion-status');
// Analytics Elements
const analyticsBtn = document.getElementById('analyticsBtn');
const analyticsModal = document.getElementById('analyticsModal');
const lastAccessedSpan = document.getElementById('lastAccessed');
const lessonProgressListUl = document.getElementById('lessonProgressList'); // Added for modal
const quizScoresListUl = document.getElementById('quizScoresList');
const overallGradeSpan = document.getElementById('overallGrade');
// Modal Navigation Elements
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// --- Storage Keys ---
const storageKeys = {
users: 'registeredUsers', // Key for the main user object containing all users
lessons: 'createdLessons', // Global lessons created by teacher
quizzes: 'createdQuizzes', // Global quizzes created by teacher
lastAccessed: `studentLastAccessed_${loggedInUsername}` // Student-specific last access
};
// --- Utility Functions (Ensure login.js is included for getUsers/saveUsers) ---
// getUsers() and saveUsers() are assumed to be available from login.js
if (typeof getUsers !== 'function' || typeof saveUsers !== 'function') {
console.error("Error: getUsers or saveUsers function not found. Make sure login.js is included before student.js");
alert("A critical error occurred. Please try refreshing the page or logging in again.");
// Optionally redirect or disable functionality
return;
}
// --- Get Current Student Data ---
// Helper to safely get the current student's data object from the main users store
function getCurrentStudentData() {
const users = getUsers();
const studentData = users[loggedInUsername];
if (studentData && studentData.role === 'student') {
// Initialize progress arrays if they don't exist (robustness)
if (!Array.isArray(studentData.quizScores)) {
studentData.quizScores = [];
}
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
return studentData;
}
console.error("Could not find valid student data for username:", loggedInUsername);
// Maybe redirect or show error if student data is corrupted/missing
alert("Error: Could not load your data. Please try logging in again.");
logout(); // Log out if data is missing
return null; // Return null to indicate failure
}
// --- Track Last Accessed ---
function recordLastAccessed() {
const now = new Date();
localStorage.setItem(storageKeys.lastAccessed, now.toISOString());
}
// --- Lesson Display & Tracking ---
function updateCreatedLessons() {
const globalLessons = JSON.parse(localStorage.getItem(storageKeys.lessons) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdLessonsDiv.innerHTML = ''; // Clear existing lessons
if (globalLessons.length === 0) {
createdLessonsDiv.innerHTML = '<p>No lessons available.</p>';
return;
}
globalLessons.forEach((lesson, index) => {
// Basic validation
const title = lesson.title || 'Untitled Lesson';
const content = lesson.content || 'No content.';
const lessonId = `lesson-${index}`; // Simple ID based on index
// Check student's progress for this lesson
const progressEntry = studentData.lessonProgress.find(p => p.lessonName === title);
const isRead = progressEntry && (progressEntry.status === 'read' || progressEntry.status === 'completed'); // Consider both 'read' and 'completed' as read
const lessonDiv = document.createElement('div');
lessonDiv.classList.add('lesson');
lessonDiv.innerHTML = `
<h4>${title}</h4>
<p>${content}</p>
<button class="mark-read-btn" data-lesson-title="${title}" ${isRead ? 'disabled' : ''}>
${isRead ? 'Read' : 'Mark as Read'}
</button>
`;
createdLessonsDiv.appendChild(lessonDiv);
});
}
// --- Event Delegation for Lesson Buttons ---
createdLessonsDiv.addEventListener('click', (event) => {
const target = event.target;
if (target.classList.contains('mark-read-btn') && !target.disabled) {
const lessonTitle = target.dataset.lessonTitle;
markLessonAsRead(lessonTitle, target);
}
});
function markLessonAsRead(lessonTitle, buttonElement) {
const users = getUsers();
const studentData = users[loggedInUsername]; // Get current data again
if (!studentData) {
alert("Error updating lesson status.");
return;
}
// Ensure lessonProgress array exists
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
// Find the progress entry or create it
let progressEntry = studentData.lessonProgress.find(p => p.lessonName === lessonTitle);
if (progressEntry) {
progressEntry.status = 'read'; // Update status to 'read'
} else {
// Add new entry if it doesn't exist
studentData.lessonProgress.push({ lessonName: lessonTitle, status: 'read' });
}
// Save the updated users object
saveUsers(users);
// Update the button state
buttonElement.disabled = true;
buttonElement.textContent = 'Read';
console.log(`Lesson "${lessonTitle}" marked as read for ${loggedInUsername}`);
// Optionally, update the analytics modal if it's open
if (analyticsModal.style.display === 'block') {
populateAnalyticsData();
}
}
// --- Quiz Display and Taking Logic ---
function updateCreatedQuizzes() {
console.log("Updating created quizzes display for student:", loggedInUsername);
const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdQuizzesDiv.innerHTML = ''; // Clear previous content
if (globalQuizzes.length === 0) {
createdQuizzesDiv.innerHTML = '<p>No quizzes available.</p>';
checkAndEnforceQuizCompletion(); // Check even if no quizzes
return;
}
globalQuizzes.forEach((quiz, index) => {
// Basic validation of quiz structure
if (!quiz || typeof quiz.quizTitle === 'undefined' || !Array.isArray(quiz.questions)) {
console.warn(`Skipping invalid quiz data at index ${index}:`, quiz);
return; // Skip rendering this invalid quiz
}
const quizTitle = quiz.quizTitle || 'Untitled Quiz';
// Check if this student has taken this quiz by looking in their main data
const resultData = studentData.quizScores.find(score => score.quizName === quizTitle);
const hasTaken = !!resultData; // True if resultData is found
console.log(`Quiz Index: ${index}, Title: ${quizTitle}, Has Taken: ${hasTaken}`);
const quizDiv = document.createElement('div');
quizDiv.classList.add('quiz');
quizDiv.id = `quiz-${index}`;
quizDiv.innerHTML = `
<h4>${quizTitle}</h4>
<p>Type: ${quiz.quizType || 'N/A'}</p>
<p>Number of questions: ${quiz.questions.length}</p>
<button class="btn take-quiz-btn" data-quiz-index="${index}" ${hasTaken ? 'disabled' : ''}>${hasTaken ? 'Quiz Taken' : 'Take Quiz'}</button>
<div class="quiz-questions-area" id="quiz-area-${index}" style="display: none;"></div>
<div class="quiz-score-area" id="score-area-${index}" style="display: ${hasTaken ? 'block' : 'none'};">
${hasTaken && resultData ? `<h3>Your Score: ${resultData.score}%</h3>` : ''}
</div>
`;
createdQuizzesDiv.appendChild(quiz_
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'student') {
alert('Access denied. Please log in as a student.');
// Ensure login.js is loaded if redirecting to index.html which might be the login page
window.location.href = 'login.html'; // Redirect if not a student
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
const quizCompletionStatusDiv = document.getElementById('quiz-completion-status');
// Analytics Elements
const analyticsBtn = document.getElementById('analyticsBtn');
const analyticsModal = document.getElementById('analyticsModal');
const lastAccessedSpan = document.getElementById('lastAccessed');
const lessonProgressListUl = document.getElementById('lessonProgressList'); // Added for modal
const quizScoresListUl = document.getElementById('quizScoresList');
const overallGradeSpan = document.getElementById('overallGrade');
// Modal Navigation Elements
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// --- Storage Keys ---
const storageKeys = {
users: 'registeredUsers', // Key for the main user object containing all users
lessons: 'createdLessons', // Global lessons created by teacher
quizzes: 'createdQuizzes', // Global quizzes created by teacher
lastAccessed: `studentLastAccessed_${loggedInUsername}` // Student-specific last access
};
// --- Utility Functions (Ensure login.js is included for getUsers/saveUsers) ---
// getUsers() and saveUsers() are assumed to be available from login.js
if (typeof getUsers !== 'function' || typeof saveUsers !== 'function') {
console.error("Error: getUsers or saveUsers function not found. Make sure login.js is included before student.js");
alert("A critical error occurred. Please try refreshing the page or logging in again.");
// Optionally redirect or disable functionality
return;
}
// --- Get Current Student Data ---
// Helper to safely get the current student's data object from the main users store
function getCurrentStudentData() {
const users = getUsers();
const studentData = users[loggedInUsername];
if (studentData && studentData.role === 'student') {
// Initialize progress arrays if they don't exist (robustness)
if (!Array.isArray(studentData.quizScores)) {
studentData.quizScores = [];
}
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
return studentData;
}
console.error("Could not find valid student data for username:", loggedInUsername);
// Maybe redirect or show error if student data is corrupted/missing
alert("Error: Could not load your data. Please try logging in again.");
logout(); // Log out if data is missing
return null; // Return null to indicate failure
}
// --- Track Last Accessed ---
function recordLastAccessed() {
const now = new Date();
localStorage.setItem(storageKeys.lastAccessed, now.toISOString());
}
// --- Lesson Display & Tracking ---
function updateCreatedLessons() {
const globalLessons = JSON.parse(localStorage.getItem(storageKeys.lessons) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdLessonsDiv.innerHTML = ''; // Clear existing lessons
if (globalLessons.length === 0) {
createdLessonsDiv.innerHTML = '<p>No lessons available.</p>';
return;
}
globalLessons.forEach((lesson, index) => {
// Basic validation
const title = lesson.title || 'Untitled Lesson';
const content = lesson.content || 'No content.';
const lessonId = `lesson-${index}`; // Simple ID based on index
// Check student's progress for this lesson
const progressEntry = studentData.lessonProgress.find(p => p.lessonName === title);
const isRead = progressEntry && (progressEntry.status === 'read' || progressEntry.status === 'completed'); // Consider both 'read' and 'completed' as read
const lessonDiv = document.createElement('div');
lessonDiv.classList.add('lesson');
lessonDiv.innerHTML = `
<h4>${title}</h4>
<p>${content}</p>
<button class="mark-read-btn" data-lesson-title="${title}" ${isRead ? 'disabled' : ''}>
${isRead ? 'Read' : 'Mark as Read'}
</button>
`;
createdLessonsDiv.appendChild(lessonDiv);
});
}
// --- Event Delegation for Lesson Buttons ---
createdLessonsDiv.addEventListener('click', (event) => {
const target = event.target;
if (target.classList.contains('mark-read-btn') && !target.disabled) {
const lessonTitle = target.dataset.lessonTitle;
markLessonAsRead(lessonTitle, target);
}
});
function markLessonAsRead(lessonTitle, buttonElement) {
const users = getUsers();
const studentData = users[loggedInUsername]; // Get current data again
if (!studentData) {
alert("Error updating lesson status.");
return;
}
// Ensure lessonProgress array exists
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
// Find the progress entry or create it
let progressEntry = studentData.lessonProgress.find(p => p.lessonName === lessonTitle);
if (progressEntry) {
progressEntry.status = 'read'; // Update status to 'read'
} else {
// Add new entry if it doesn't exist
studentData.lessonProgress.push({ lessonName: lessonTitle, status: 'read' });
}
// Save the updated users object
saveUsers(users);
// Update the button state
buttonElement.disabled = true;
buttonElement.textContent = 'Read';
console.log(`Lesson "${lessonTitle}" marked as read for ${loggedInUsername}`);
// Optionally, update the analytics modal if it's open
if (analyticsModal.style.display === 'block') {
populateAnalyticsData();
}
}
// --- Quiz Display and Taking Logic ---
function updateCreatedQuizzes() {
console.log("Updating created quizzes display for student:", loggedInUsername);
const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdQuizzesDiv.innerHTML = ''; // Clear previous content
if (globalQuizzes.length === 0) {
createdQuizzesDiv.innerHTML = '<p>No quizzes available.</p>';
checkAndEnforceQuizCompletion(); // Check even if no quizzes
return;
}
globalQuizzes.forEach((quiz, index) => {
// Basic validation of quiz structure
if (!quiz || typeof quiz.quizTitle === 'undefined' || !Array.isArray(quiz.questions)) {
console.warn(`Skipping invalid quiz data at index ${index}:`, quiz);
return; // Skip rendering this invalid quiz
}
const quizTitle = quiz.quizTitle || 'Untitled Quiz';
// Check if this student has taken this quiz by looking in their main data
const resultData = studentData.quizScores.find(score => score.quizName === quizTitle);
const hasTaken = !!resultData; // True if resultData is found
console.log(`Quiz Index: ${index}, Title: ${quizTitle}, Has Taken: ${hasTaken}`);
const quizDiv = document.createElement('div');
quizDiv.classList.add('quiz');
quizDiv.id = `quiz-${index}`;
quizDiv.innerHTML = `
<h4>${quizTitle}</h4>
<p>Type: ${quiz.quizType || 'N/A'}</p>
<p>Number of questions: ${quiz.questions.length}</p>
<button class="btn take-quiz-btn" data-quiz-index="${index}" ${hasTaken ? 'disabled' : ''}>${hasTaken ? 'Quiz Taken' : 'Take Quiz'}</button>
<div class="quiz-questions-area" id="quiz-area-${index}" style="display: none;"></div>
<div class="quiz-score-area" id="score-area-${index}" style="display: ${hasTaken ? 'block' : 'none'};">
${hasTaken && resultData ? `<h3>Your Score: ${resultData.score}%</h3>` : ''}
</div>
`;
createdQuizzesDiv.appendChild(quiz_
Okay, here is the complete code for student.js.
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'student') {
alert('Access denied. Please log in as a student.');
// Ensure login.js is loaded if redirecting to index.html which might be the login page
window.location.href = 'login.html'; // Redirect if not a student
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
const quizCompletionStatusDiv = document.getElementById('quiz-completion-status');
// Analytics Elements
const analyticsBtn = document.getElementById('analyticsBtn');
const analyticsModal = document.getElementById('analyticsModal');
const lastAccessedSpan = document.getElementById('lastAccessed');
const lessonProgressListUl = document.getElementById('lessonProgressList'); // Added for modal
const quizScoresListUl = document.getElementById('quizScoresList');
const overallGradeSpan = document.getElementById('overallGrade');
// Modal Navigation Elements
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// --- Storage Keys ---
const storageKeys = {
users: 'registeredUsers', // Key for the main user object containing all users
lessons: 'createdLessons', // Global lessons created by teacher
quizzes: 'createdQuizzes', // Global quizzes created by teacher
lastAccessed: `studentLastAccessed_${loggedInUsername}` // Student-specific last access
};
// --- Utility Functions (Ensure login.js is included for getUsers/saveUsers) ---
// getUsers() and saveUsers() are assumed to be available from login.js
if (typeof getUsers !== 'function' || typeof saveUsers !== 'function') {
console.error("Error: getUsers or saveUsers function not found. Make sure login.js is included before student.js");
alert("A critical error occurred. Please try refreshing the page or logging in again.");
// Optionally redirect or disable functionality
return;
}
// --- Get Current Student Data ---
// Helper to safely get the current student's data object from the main users store
function getCurrentStudentData() {
const users = getUsers();
const studentData = users[loggedInUsername];
if (studentData && studentData.role === 'student') {
// Initialize progress arrays if they don't exist (robustness)
if (!Array.isArray(studentData.quizScores)) {
studentData.quizScores = [];
}
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
return studentData;
}
console.error("Could not find valid student data for username:", loggedInUsername);
// Maybe redirect or show error if student data is corrupted/missing
alert("Error: Could not load your data. Please try logging in again.");
logout(); // Log out if data is missing
return null; // Return null to indicate failure
}
// --- Track Last Accessed ---
function recordLastAccessed() {
const now = new Date();
localStorage.setItem(storageKeys.lastAccessed, now.toISOString());
}
// --- Lesson Display & Tracking ---
function updateCreatedLessons() {
const globalLessons = JSON.parse(localStorage.getItem(storageKeys.lessons) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdLessonsDiv.innerHTML = ''; // Clear existing lessons
if (globalLessons.length === 0) {
createdLessonsDiv.innerHTML = '<p>No lessons available.</p>';
return;
}
globalLessons.forEach((lesson, index) => {
// Basic validation
const title = lesson.title || 'Untitled Lesson';
const content = lesson.content || 'No content.';
const lessonId = `lesson-${index}`; // Simple ID based on index
// Check student's progress for this lesson
const progressEntry = studentData.lessonProgress.find(p => p.lessonName === title);
const isRead = progressEntry && (progressEntry.status === 'read' || progressEntry.status === 'completed'); // Consider both 'read' and 'completed' as read
const lessonDiv = document.createElement('div');
lessonDiv.classList.add('lesson');
lessonDiv.innerHTML = `
<h4>${title}</h4>
<p>${content}</p>
<button class="mark-read-btn" data-lesson-title="${title}" ${isRead ? 'disabled' : ''}>
${isRead ? 'Read' : 'Mark as Read'}
</button>
`;
createdLessonsDiv.appendChild(lessonDiv);
});
}
// --- Event Delegation for Lesson Buttons ---
createdLessonsDiv.addEventListener('click', (event) => {
const target = event.target;
if (target.classList.contains('mark-read-btn') && !target.disabled) {
const lessonTitle = target.dataset.lessonTitle;
markLessonAsRead(lessonTitle, target);
}
});
function markLessonAsRead(lessonTitle, buttonElement) {
const users = getUsers();
const studentData = users[loggedInUsername]; // Get current data again
if (!studentData) {
alert("Error updating lesson status.");
return;
}
// Ensure lessonProgress array exists
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
// Find the progress entry or create it
let progressEntry = studentData.lessonProgress.find(p => p.lessonName === lessonTitle);
if (progressEntry) {
progressEntry.status = 'read'; // Update status to 'read'
} else {
// Add new entry if it doesn't exist
studentData.lessonProgress.push({ lessonName: lessonTitle, status: 'read' });
}
// Save the updated users object
saveUsers(users);
// Update the button state
buttonElement.disabled = true;
buttonElement.textContent = 'Read';
console.log(`Lesson "${lessonTitle}" marked as read for ${loggedInUsername}`);
// Optionally, update the analytics modal if it's open
if (analyticsModal.style.display === 'block') {
populateAnalyticsData();
}
}
// --- Quiz Display and Taking Logic ---
function updateCreatedQuizzes() {
console.log("Updating created quizzes display for student:", loggedInUsername);
const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdQuizzesDiv.innerHTML = ''; // Clear previous content
if (globalQuizzes.length === 0) {
createdQuizzesDiv.innerHTML = '<p>No quizzes available.</p>';
checkAndEnforceQuizCompletion(); // Check even if no quizzes
return;
}
globalQuizzes.forEach((quiz, index) => {
// Basic validation of quiz structure
if (!quiz || typeof quiz.quizTitle === 'undefined' || !Array.isArray(quiz.questions)) {
console.warn(`Skipping invalid quiz data at index ${index}:`, quiz);
return; // Skip rendering this invalid quiz
}
const quizTitle = quiz.quizTitle || 'Untitled Quiz';
// Check if this student has taken this quiz by looking in their main data
const resultData = studentData.quizScores.find(score => score.quizName === quizTitle);
const hasTaken = !!resultData; // True if resultData is found
console.log(`Quiz Index: ${index}, Title: ${quizTitle}, Has Taken: ${hasTaken}`);
const quizDiv = document.createElement('div');
quizDiv.classList.add('quiz');
quizDiv.id = `quiz-${index}`;
quizDiv.innerHTML = `
<h4>${quizTitle}</h4>
<p>Type: ${quiz.quizType || 'N/A'}</p>
<p>Number of questions: ${quiz.questions.length}</p>
<button class="btn take-quiz-btn" data-quiz-index="${index}" ${hasTaken ? 'disabled' : ''}>${hasTaken ? 'Quiz Taken' : 'Take Quiz'}</button>
<div class="quiz-questions-area" id="quiz-area-${index}" style="display: none;"></div>
<div class="quiz-score-area" id="score-area-${index}" style="display: ${hasTaken ? 'block' : 'none'};">
${hasTaken && resultData ? `<h3>Your Score: ${resultData.score}%</h3>` : ''}
</div>
`;
createdQuizzesDiv.appendChild(quizDiv);
});
checkAndEnforceQuizCompletion(); // Check completion after rendering quizzes
}
// --- Event Delegation for Quiz Buttons ---
createdQuizzesDiv.addEventListener('click', (event) => {
const target = event.target; // The element that was actually clicked
// Check if the clicked element is a "take-quiz-btn" or inside one
const takeButton = target.closest('.take-quiz-btn');
if (takeButton && !takeButton.disabled) {
console.log("Take Quiz button clicked via delegation for index:", takeButton.dataset.quizIndex);
startQuiz(takeButton); // Pass the button element itself
return; // Stop further processing for this click
}
// Check if the clicked element is a "submit-quiz-btn" or inside one
const submitButton = target.closest('.submit-quiz-btn');
if (submitButton && !submitButton.disabled) {
console.log("Submit Quiz button clicked via delegation for index:", submitButton.dataset.quizIndex);
submitQuiz(submitButton); // Pass the button element itself
return; // Stop further processing for this click
}
});
function startQuiz(buttonElement) { // Accepts the button element directly
const quizIndex = buttonElement.dataset.quizIndex;
console.log('startQuiz called for index:', quizIndex);
const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]');
// Validate quiz index and data
if (quizIndex === undefined || !globalQuizzes[quizIndex] || !Array.isArray(globalQuizzes[quizIndex].questions)) {
console.error(`Invalid quiz index or data for index ${quizIndex}`);
alert("Error: Could not load quiz data.");
return;
}
const quiz = globalQuizzes[quizIndex];
const questionsArea = document.getElementById(`quiz-area-${quizIndex}`);
const scoreArea = document.getElementById(`score-area-${quizIndex}`);
const takeQuizButton = buttonElement; // The button that was clicked
if (!questionsArea || !scoreArea) {
console.error(`Could not find questionsArea or scoreArea for quiz index ${quizIndex}`);
alert("Error: Could not display quiz.");
return;
}
// Hide other open quiz forms if any, and show their "Take Quiz" buttons
document.querySelectorAll('.quiz-questions-area').forEach(area => {
if (area.id !== `quiz-area-${quizIndex}`) {
area.style.display = 'none';
const otherQuizIndex = area.id.split('-')[2];
const otherTakeButton = document.querySelector(`.take-quiz-btn[data-quiz-index="${otherQuizIndex}"]`);
// Check if the other quiz has been taken using the main student data
const studentData = getCurrentStudentData();
const otherQuizTitle = globalQuizzes[otherQuizIndex]?.quizTitle;
const otherQuizTaken = studentData?.quizScores.some(s => s.quizName === otherQuizTitle);
if (otherTakeButton && !otherQuizTaken) { // Only show if not already taken
otherTakeButton.style.display = 'inline-block';
}
}
});
questionsArea.innerHTML = ''; // Clear previous content if any
scoreArea.innerHTML = ''; // Clear score area
scoreArea.style.display = 'none'; // Hide score area
questionsArea.style.display = 'block'; // Show questions area
takeQuizButton.style_
if (!loggedInUsername || !loggedInRole || loggedInRole !== 'student') {
alert('Access denied. Please log in as a student.');
// Ensure login.js is loaded if redirecting to index.html which might be the login page
window.location.href = 'login.html'; // Redirect if not a student
return;
}
// --- End Login Check ---
// --- DOM Elements ---
const createdLessonsDiv = document.getElementById('createdLessons');
const createdQuizzesDiv = document.getElementById('createdQuizzes');
const quizCompletionStatusDiv = document.getElementById('quiz-completion-status');
// Analytics Elements
const analyticsBtn = document.getElementById('analyticsBtn');
const analyticsModal = document.getElementById('analyticsModal');
const lastAccessedSpan = document.getElementById('lastAccessed');
const lessonProgressListUl = document.getElementById('lessonProgressList'); // Added for modal
const quizScoresListUl = document.getElementById('quizScoresList');
const overallGradeSpan = document.getElementById('overallGrade');
// Modal Navigation Elements
const modalDashboardBtn = document.getElementById('modalDashboardBtn');
const modalHomeBtn = document.getElementById('modalHomeBtn');
const modalLogoutBtn = document.getElementById('modalLogoutBtn');
// --- Storage Keys ---
const storageKeys = {
users: 'registeredUsers', // Key for the main user object containing all users
lessons: 'createdLessons', // Global lessons created by teacher
quizzes: 'createdQuizzes', // Global quizzes created by teacher
lastAccessed: `studentLastAccessed_${loggedInUsername}` // Student-specific last access
};
// --- Utility Functions (Ensure login.js is included for getUsers/saveUsers) ---
// getUsers() and saveUsers() are assumed to be available from login.js
if (typeof getUsers !== 'function' || typeof saveUsers !== 'function') {
console.error("Error: getUsers or saveUsers function not found. Make sure login.js is included before student.js");
alert("A critical error occurred. Please try refreshing the page or logging in again.");
// Optionally redirect or disable functionality
return;
}
// --- Get Current Student Data ---
// Helper to safely get the current student's data object from the main users store
function getCurrentStudentData() {
const users = getUsers();
const studentData = users[loggedInUsername];
if (studentData && studentData.role === 'student') {
// Initialize progress arrays if they don't exist (robustness)
if (!Array.isArray(studentData.quizScores)) {
studentData.quizScores = [];
}
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
return studentData;
}
console.error("Could not find valid student data for username:", loggedInUsername);
// Maybe redirect or show error if student data is corrupted/missing
alert("Error: Could not load your data. Please try logging in again.");
logout(); // Log out if data is missing
return null; // Return null to indicate failure
}
// --- Track Last Accessed ---
function recordLastAccessed() {
const now = new Date();
localStorage.setItem(storageKeys.lastAccessed, now.toISOString());
}
// --- Lesson Display & Tracking ---
function updateCreatedLessons() {
const globalLessons = JSON.parse(localStorage.getItem(storageKeys.lessons) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdLessonsDiv.innerHTML = ''; // Clear existing lessons
if (globalLessons.length === 0) {
createdLessonsDiv.innerHTML = '<p>No lessons available.</p>';
return;
}
globalLessons.forEach((lesson, index) => {
// Basic validation
const title = lesson.title || 'Untitled Lesson';
const content = lesson.content || 'No content.';
const lessonId = `lesson-${index}`; // Simple ID based on index
// Check student's progress for this lesson
const progressEntry = studentData.lessonProgress.find(p => p.lessonName === title);
const isRead = progressEntry && (progressEntry.status === 'read' || progressEntry.status === 'completed'); // Consider both 'read' and 'completed' as read
const lessonDiv = document.createElement('div');
lessonDiv.classList.add('lesson');
lessonDiv.innerHTML = `
<h4>${title}</h4>
<p>${content}</p>
<button class="mark-read-btn" data-lesson-title="${title}" ${isRead ? 'disabled' : ''}>
${isRead ? 'Read' : 'Mark as Read'}
</button>
`;
createdLessonsDiv.appendChild(lessonDiv);
});
}
// --- Event Delegation for Lesson Buttons ---
createdLessonsDiv.addEventListener('click', (event) => {
const target = event.target;
if (target.classList.contains('mark-read-btn') && !target.disabled) {
const lessonTitle = target.dataset.lessonTitle;
markLessonAsRead(lessonTitle, target);
}
});
function markLessonAsRead(lessonTitle, buttonElement) {
const users = getUsers();
const studentData = users[loggedInUsername]; // Get current data again
if (!studentData) {
alert("Error updating lesson status.");
return;
}
// Ensure lessonProgress array exists
if (!Array.isArray(studentData.lessonProgress)) {
studentData.lessonProgress = [];
}
// Find the progress entry or create it
let progressEntry = studentData.lessonProgress.find(p => p.lessonName === lessonTitle);
if (progressEntry) {
progressEntry.status = 'read'; // Update status to 'read'
} else {
// Add new entry if it doesn't exist
studentData.lessonProgress.push({ lessonName: lessonTitle, status: 'read' });
}
// Save the updated users object
saveUsers(users);
// Update the button state
buttonElement.disabled = true;
buttonElement.textContent = 'Read';
console.log(`Lesson "${lessonTitle}" marked as read for ${loggedInUsername}`);
// Optionally, update the analytics modal if it's open
if (analyticsModal.style.display === 'block') {
populateAnalyticsData();
}
}
// --- Quiz Display and Taking Logic ---
function updateCreatedQuizzes() {
console.log("Updating created quizzes display for student:", loggedInUsername);
const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]');
const studentData = getCurrentStudentData();
if (!studentData) return; // Stop if student data failed to load
createdQuizzesDiv.innerHTML = ''; // Clear previous content
if (globalQuizzes.length === 0) {
createdQuizzesDiv.innerHTML = '<p>No quizzes available.</p>';
checkAndEnforceQuizCompletion(); // Check even if no quizzes
return;
}
globalQuizzes.forEach((quiz, index) => {
// Basic validation of quiz structure
if (!quiz || typeof quiz.quizTitle === 'undefined' || !Array.isArray(quiz.questions)) {
console.warn(`Skipping invalid quiz data at index ${index}:`, quiz);
return; // Skip rendering this invalid quiz
}
const quizTitle = quiz.quizTitle || 'Untitled Quiz';
// Check if this student has taken this quiz by looking in their main data
const resultData = studentData.quizScores.find(score => score.quizName === quizTitle);
const hasTaken = !!resultData; // True if resultData is found
console.log(`Quiz Index: ${index}, Title: ${quizTitle}, Has Taken: ${hasTaken}`);
const quizDiv = document.createElement('div');
quizDiv.classList.add('quiz');
quizDiv.id = `quiz-${index}`;
quizDiv.innerHTML = `
<h4>${quizTitle}</h4>
<p>Type: ${quiz.quizType || 'N/A'}</p>
<p>Number of questions: ${quiz.questions.length}</p>
<button class="btn take-quiz-btn" data-quiz-index="${index}" ${hasTaken ? 'disabled' : ''}>${hasTaken ? 'Quiz Taken' : 'Take Quiz'}</button>
<div class="quiz-questions-area" id="quiz-area-${index}" style="display: none;"></div>
<div class="quiz-score-area" id="score-area-${index}" style="display: ${hasTaken ? 'block' : 'none'};">
${hasTaken && resultData ? `<h3>Your Score: ${resultData.score}%</h3>` : ''}
</div>
`;
createdQuizzesDiv.appendChild(quizDiv);
});
checkAndEnforceQuizCompletion(); // Check completion after rendering quizzes
}
// --- Event Delegation for Quiz Buttons ---
createdQuizzesDiv.addEventListener('click', (event) => {
const target = event.target; // The element that was actually clicked
// Check if the clicked element is a "take-quiz-btn" or inside one
const takeButton = target.closest('.take-quiz-btn');
if (takeButton && !takeButton.disabled) {
console.log("Take Quiz button clicked via delegation for index:", takeButton.dataset.quizIndex);
startQuiz(takeButton); // Pass the button element itself
return; // Stop further processing for this click
}
// Check if the clicked element is a "submit-quiz-btn" or inside one
const submitButton = target.closest('.submit-quiz-btn');
if (submitButton && !submitButton.disabled) {
console.log("Submit Quiz button clicked via delegation for index:", submitButton.dataset.quizIndex);
submitQuiz(submitButton); // Pass the button element itself
return; // Stop further processing for this click
}
});
function startQuiz(buttonElement) { // Accepts the button element directly
const quizIndex = buttonElement.dataset.quizIndex;
console.log('startQuiz called for index:', quizIndex);
const globalQuizzes = JSON.parse(localStorage.getItem(storageKeys.quizzes) || '[]');
// Validate quiz index and data
if (quizIndex === undefined || !globalQuizzes[quizIndex] || !Array.isArray(globalQuizzes[quizIndex].questions)) {
console.error(`Invalid quiz index or data for index ${quizIndex}`);
alert("Error: Could not load quiz data.");
return;
}
const quiz = globalQuizzes[quizIndex];
const questionsArea = document.getElementById(`quiz-area-${quizIndex}`);
const scoreArea = document.getElementById(`score-area-${quizIndex}`);
const takeQuizButton = buttonElement; // The button that was clicked
if (!questionsArea || !scoreArea) {
console.error(`Could not find questionsArea or scoreArea for quiz index ${quizIndex}`);
alert("Error: Could not display quiz.");
return;
}
// Hide other open quiz forms if any, and show their "Take Quiz" buttons
document.querySelectorAll('.quiz-questions-area').forEach(area => {
if (area.id !== `quiz-area-${quizIndex}`) {
area.style.display = 'none';
const otherQuizIndex = area.id.split('-')[2];
const otherTakeButton = document.querySelector(`.take-quiz-btn[data-quiz-index="${otherQuizIndex}"]`);
// Check if the other quiz has been taken using the main student data
const studentData = getCurrentStudentData();
const otherQuizTitle = globalQuizzes[otherQuizIndex]?.quizTitle;
const otherQuizTaken = studentData?.quizScores.some(s => s.quizName === otherQuizTitle);
if (otherTakeButton && !otherQuizTaken) { // Only show if not already taken
otherTakeButton.style.display = 'inline-block';
}
}
});
questionsArea.innerHTML = ''; // Clear previous content if any
scoreArea.innerHTML = ''; // Clear score area
scoreArea.style.display = 'none'; // Hide score area
questionsArea.style.display = 'block'; // Show questions area
takeQuizButton.style_
Okay, here is the complete code for student.js.
This provides the complete code for student.js along with all the other necessary files (teacher.html, teacher.css, teacher.js, student.html, student.css, login.html, login.js, login.css, homepage.html) to make the application functional.
Okay, I understand. You want to add a "Logout" functionality to the parent's view that redirects the user back to the provided login.html page.
Since the first HTML file you provided (parent-access.html) is just for finding the student, the logout button logically belongs on the next page – the actual dashboard displaying the student's information.
I will:
parent-access.html file for finding the student.parent-dashboard.html file where the student's data will be shown after successful verification. This page will contain the "Logout" button.parent.js to handle the verification and redirection to the dashboard.parent-dashboard.html to display data and handle the logout action.login.html and login.js.Here's the setup:
Explanation:
parent-access.html: This remains the initial page for parents. It prompts for the student's full name and ID.parent.js:
verifyStudent function now checks the entered name and ID against the registeredUsers data fetched using getUsers() from login.js.role: 'student' and matching fullName and studentId.username and fullName in sessionStorage and redirects to parent-dashboard.html.parent-dashboard.html:
DOMContentLoaded:
verifiedStudentUsername and verifiedStudentFullName from sessionStorage. If not found, it redirects back to the access page.getUsers() to get all user data and finds the specific student's record.logout function clears the relevant sessionStorage items and redirects the browser to login.html.parent.css: Basic styling is provided for both parent pages.login.html & login.js: Updated to use the versions you provided, ensuring the parent role is handled correctly during login and signup, and that student signup includes fullName and studentId. The login function now redirects parents to parent-access.html.login.css: Included for styling the login/signup page.Okay, I understand you want to ensure that pressing a logout button returns the user to the login page.
However, the code you provided (parent-access.html) is the page where the parent finds the student record. Logically, a "Logout" button doesn't belong here because the parent isn't necessarily "logged in" to this specific page. They usually log in first (on login.html), might be redirected here, and then proceed to the actual dashboard after finding the student.
The "Logout" button makes the most sense on the page that displays the student's sensitive information (the parent-dashboard.html page we created in the previous step). That's where the parent's "session" of viewing the data exists.
The parent-access.html page already has a "Back to Login" link, which serves the purpose of returning to the login screen from this intermediate step.
Therefore, the logout functionality is correctly placed in the parent-dashboard.html file from the previous response. When the parent is viewing the dashboard and clicks "Logout", the JavaScript in parent-dashboard.html will clear the session storage and redirect them to login.html.
Here is the relevant part of parent-dashboard.html again, showing the logout button and its associated JavaScript:
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Parent Dashboard</title> <link rel="stylesheet" href="parent.css"> <!-- Use parent CSS --> </head> <body> <div class="dashboard-container"> <div class="header"> <h1>Parent Dashboard</h1> <!-- LOGOUT BUTTON IS HERE --> <button id="logoutBtn" class="logout-button">Logout</button> </div> <h2 id="studentNameDisplay">Viewing Progress for: Loading...</h2>
<!-- ... (sections for lesson progress, quiz scores, etc.) ... -->
</div>
<script src="login.js"></script> <!-- Include login.js for getUsers function -->
<script>
document.addEventListener('DOMContentLoaded', () => {
// ... (code to get student data and display it) ...
const logoutBtn = document.getElementById('logoutBtn');
// --- Logout Functionality ---
logoutBtn.addEventListener('click', logout); // Attach listener
});
// LOGOUT FUNCTION IS HERE
function logout() {
// Clear relevant session storage items
sessionStorage.removeItem('loggedInUsername'); // If parent logged in
sessionStorage.removeItem('loggedInRole'); // If parent logged in
sessionStorage.removeItem('verifiedStudentUsername');
sessionStorage.removeItem('verifiedStudentFullName');
// Redirect to the login page
window.location.href = 'login.html';
}
</script>
<h2 id="studentNameDisplay">Viewing Progress for: Loading...</h2>
<!-- ... (sections for lesson progress, quiz scores, etc.) ... -->
</div>
<script src="login.js"></script> <!-- Include login.js for getUsers function -->
<script>
document.addEventListener('DOMContentLoaded', () => {
// ... (code to get student data and display it) ...
const logoutBtn = document.getElementById('logoutBtn');
// --- Logout Functionality ---
logoutBtn.addEventListener('click', logout); // Attach listener
});
// LOGOUT FUNCTION IS HERE
function logout() {
// Clear relevant session storage items
sessionStorage.removeItem('loggedInUsername'); // If parent logged in
sessionStorage.removeItem('loggedInRole'); // If parent logged in
sessionStorage.removeItem('verifiedStudentUsername');
sessionStorage.removeItem('verifiedStudentFullName');
// Redirect to the login page
window.location.href = 'login.html';
}
</script>
So, to reiterate:
login.html.parent-access.html.parent.js verifies the student and redirects to parent-dashboard.html.parent-dashboard.html, the parent views the data.parent-dashboard.html.logout function in parent-dashboard.html runs, clearing session data and redirecting back to login.html.Okay, I will add a "Logout" button directly to the parent-access.html code you provided and ensure clicking it redirects to login.html.
I'll modify parent-access.html to include the button and update parent.js to handle the click event for this new button.
Now, the parent-access.html page includes a "Logout" button. Clicking it will execute the logout function defined in parent.js, clear the session storage, and redirect the user to login.html.