Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>UC Math Evaluation System</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| } | |
| .evaluation-card { | |
| transition: all 0.3s ease; | |
| } | |
| .evaluation-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 20px rgba(0,0,0,0.1); | |
| } | |
| .shake { | |
| animation: shake 0.5s; | |
| } | |
| @keyframes shake { | |
| 0%, 100% { transform: trans | |
| lateX(0); } | |
| 10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); } | |
| 20%, 40%, 60%, 80% { transform: translateX(5px); } | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen bg-gray-100"> | |
| <!-- Main Container --> | |
| <div id="app" class="container mx-auto px-4 py-8"> | |
| <!-- Login Screen --> | |
| <div id="login-screen" class="max-w-md mx-auto"> | |
| <div class="gradient-bg rounded-xl shadow-xl overflow-hidden"> | |
| <div class="px-10 py-12"> | |
| <div class="text-center mb-8"> | |
| <h1 class="text-3xl font-bold text-white">UC Math Evaluation</h1> | |
| <p class="text-white opacity-80 mt-2">Student & Teacher Portal</p> | |
| </div> | |
| <form id="login-form" class="space-y-6"> | |
| <div> | |
| <label for="username" class="block text-sm font-medium text-white">Username</label> | |
| <div class="mt-1 relative rounded-md shadow-sm"> | |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <i class="fas fa-user text-gray-300"></i> | |
| </div> | |
| <input type="text" id="username" name="username" required | |
| class="py-3 pl-10 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500"> | |
| </div> | |
| </div> | |
| <div> | |
| <label for="password" class="block text-sm font-medium text-white">Password</label> | |
| <div class="mt-1 relative rounded-md shadow-sm"> | |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <i class="fas fa-lock text-gray-300"></i> | |
| </div> | |
| <input type="password" id="password" name="password" required | |
| class="py-3 pl-10 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500"> | |
| </div> | |
| </div> | |
| <div> | |
| <button type="submit" | |
| class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-indigo-700 bg-white hover:bg-indigo-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-all"> | |
| Sign in | |
| </button> | |
| </div> | |
| </form> | |
| <div id="login-error" class="mt-4 hidden"> | |
| <div class="bg-red-50 border-l-4 border-red-400 p-4"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-exclamation-circle text-red-400"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm text-red-700" id="error-message">Invalid username or password</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Student Dashboard (Hidden by default) --> | |
| <div id="student-dashboard" class="hidden"> | |
| <div class="flex justify-between items-center mb-8"> | |
| <h1 class="text-3xl font-bold text-gray-800">Your Math Evaluations</h1> | |
| <button id="logout-btn" class="flex items-center text-gray-600 hover:text-gray-900"> | |
| <i class="fas fa-sign-out-alt mr-2"></i> Logout | |
| </button> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="p-6"> | |
| <div class="flex items-center mb-6"> | |
| <div class="h-12 w-12 rounded-full bg-indigo-100 flex items-center justify-center"> | |
| <i class="fas fa-user-graduate text-indigo-600 text-xl"></i> | |
| </div> | |
| <div class="ml-4"> | |
| <h2 class="text-xl font-semibold text-gray-800" id="student-name">John Doe</h2> | |
| <p class="text-gray-600">Student ID: <span id="student-id">S12345</span></p> | |
| </div> | |
| </div> | |
| <div id="evaluations-container" class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <!-- Evaluations will be loaded here --> | |
| </div> | |
| <div id="no-evaluations" class="text-center py-12 hidden"> | |
| <i class="fas fa-book-open text-gray-300 text-5xl mb-4"></i> | |
| <h3 class="text-lg font-medium text-gray-500">No evaluations available</h3> | |
| <p class="text-gray-400 mt-1">Your teacher hasn't uploaded any evaluations yet.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Teacher Dashboard (Hidden by default) --> | |
| <div id="teacher-dashboard" class="hidden"> | |
| <div class="flex justify-between items-center mb-8"> | |
| <h1 class="text-3xl font-bold text-gray-800">Teacher Control Panel</h1> | |
| <button id="teacher-logout-btn" class="flex items-center text-gray-600 hover:text-gray-900"> | |
| <i class="fas fa-sign-out-alt mr-2"></i> Logout | |
| </button> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8"> | |
| <div class="p-6"> | |
| <div class="flex items-center mb-6"> | |
| <div class="h-12 w-12 rounded-full bg-purple-100 flex items-center justify-center"> | |
| <i class="fas fa-chalkboard-teacher text-purple-600 text-xl"></i> | |
| </div> | |
| <div class="ml-4"> | |
| <h2 class="text-xl font-semibold text-gray-800">Prof. Shaimaa Robaa</h2> | |
| <p class="text-gray-600">Math Department</p> | |
| </div> | |
| </div> | |
| <div class="border-b border-gray-200"> | |
| <nav class="-mb-px flex space-x-8"> | |
| <button id="manage-students-tab" class="border-indigo-500 text-indigo-600 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"> | |
| Manage Students | |
| </button> | |
| <button id="upload-evaluations-tab" class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"> | |
| Upload Evaluations | |
| </button> | |
| </nav> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Manage Students Panel --> | |
| <div id="manage-students-panel"> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden mb-6"> | |
| <div class="p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Add New Student</h2> | |
| <form id="add-student-form" class="space-y-4"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div> | |
| <label for="student-firstname" class="block text-sm font-medium text-gray-700">First Name</label> | |
| <input type="text" id="student-firstname" name="firstname" required | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"> | |
| </div> | |
| <div> | |
| <label for="student-lastname" class="block text-sm font-medium text-gray-700">Last Name</label> | |
| <input type="text" id="student-lastname" name="lastname" required | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"> | |
| </div> | |
| </div> | |
| <div> | |
| <label for="student-email" class="block text-sm font-medium text-gray-700">Email</label> | |
| <input type="email" id="student-email" name="email" required | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div> | |
| <label for="student-username" class="block text-sm font-medium text-gray-700">Username</label> | |
| <input type="text" id="student-username" name="username" required | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"> | |
| </div> | |
| <div> | |
| <label for="student-password" class="block text-sm font-medium text-gray-700">Password</label> | |
| <input type="password" id="student-password" name="password" required | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"> | |
| </div> | |
| </div> | |
| <div class="pt-2"> | |
| <button type="submit" | |
| class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> | |
| Add Student | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Student List</h2> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Username</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody id="student-list" class="bg-white divide-y divide-gray-200"> | |
| <!-- Student list will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div id="no-students" class="text-center py-12 hidden"> | |
| <i class="fas fa-user-graduate text-gray-300 text-5xl mb-4"></i> | |
| <h3 class="text-lg font-medium text-gray-500">No students added</h3> | |
| <p class="text-gray-400 mt-1">Add your first student using the form above.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Upload Evaluations Panel (Hidden by default) --> | |
| <div id="upload-evaluations-panel" class="hidden"> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden mb-6"> | |
| <div class="p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Upload New Evaluation</h2> | |
| <form id="upload-evaluation-form" class="space-y-4"> | |
| <div> | |
| <label for="evaluation-title" class="block text-sm font-medium text-gray-700">Title</label> | |
| <input type="text" id="evaluation-title" name="title" required | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"> | |
| </div> | |
| <div> | |
| <label for="evaluation-description" class="block text-sm font-medium text-gray-700">Description</label> | |
| <textarea id="evaluation-description" name="description" rows="3" | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"></textarea> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div> | |
| <label for="evaluation-date" class="block text-sm font-medium text-gray-700">Due Date</label> | |
| <input type="date" id="evaluation-date" name="date" required | |
| class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 py-2 px-3 border"> | |
| </div> | |
| <div> | |
| <label for="evaluation-file" class="block text-sm font-medium text-gray-700">Evaluation File</label> | |
| <div class="mt-1 flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md"> | |
| <div class="space-y-1 text-center"> | |
| <div class="flex text-sm text-gray-600"> | |
| <label for="file-upload" class="relative cursor-pointer bg-white rounded-md font-medium text-indigo-600 hover:text-indigo-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500"> | |
| <span>Upload a file</span> | |
| <input id="file-upload" name="file-upload" type="file" class="sr-only"> | |
| </label> | |
| <p class="pl-1">or drag and drop</p> | |
| </div> | |
| <p class="text-xs text-gray-500">PDF, DOCX up to 10MB</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="pt-2"> | |
| <button type="submit" | |
| class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> | |
| Upload Evaluation | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="p-6"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Recent Evaluations</h2> | |
| <div id="teacher-evaluations-container" class="space-y-4"> | |
| <!-- Teacher's evaluations will be loaded here --> | |
| </div> | |
| <div id="no-teacher-evaluations" class="text-center py-12 hidden"> | |
| <i class="fas fa-book text-gray-300 text-5xl mb-4"></i> | |
| <h3 class="text-lg font-medium text-gray-500">No evaluations uploaded</h3> | |
| <p class="text-gray-400 mt-1">Upload your first evaluation using the form above.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Database keys for localStorage | |
| const DB_KEYS = { | |
| STUDENTS: 'uc_math_students', | |
| EVALUATIONS: 'uc_math_evaluations' | |
| }; | |
| // Initialize database with default data if not exists | |
| function initializeDatabase() { | |
| if (!localStorage.getItem(DB_KEYS.STUDENTS)) { | |
| const defaultStudents = [ | |
| { id: 'S1001', username: 'student1', password: 'password1', name: 'Alice Johnson', email: 'alice@uc.edu' }, | |
| { id: 'S1002', username: 'student2', password: 'password2', name: 'Bob Smith', email: 'bob@uc.edu' }, | |
| { id: 'S1003', username: 'student3', password: 'password3', name: 'Charlie Brown', email: 'charlie@uc.edu' } | |
| ]; | |
| localStorage.setItem(DB_KEYS.STUDENTS, JSON.stringify(defaultStudents)); | |
| } | |
| if (!localStorage.getItem(DB_KEYS.EVALUATIONS)) { | |
| const defaultEvaluations = [ | |
| { | |
| id: 'E101', | |
| title: 'Linear Algebra Midterm', | |
| description: 'Covers chapters 1-4 on vector spaces and linear transformations', | |
| date: '2023-11-15', | |
| file: 'linear-algebra-midterm.pdf', | |
| assignedTo: ['S1001', 'S1002', 'S1003'], | |
| status: { | |
| 'S1001': 'Submitted', | |
| 'S1002': 'Pending', | |
| 'S1003': 'Submitted' | |
| } | |
| }, | |
| { | |
| id: 'E102', | |
| title: 'Calculus Assignment 3', | |
| description: 'Integration techniques and applications', | |
| date: '2023-11-22', | |
| file: 'calculus-assignment3.pdf', | |
| assignedTo: ['S1001', 'S1002'], | |
| status: { | |
| 'S1001': 'Pending', | |
| 'S1002': 'Submitted' | |
| } | |
| } | |
| ]; | |
| localStorage.setItem(DB_KEYS.EVALUATIONS, JSON.stringify(defaultEvaluations)); | |
| } | |
| } | |
| // Database functions | |
| const database = { | |
| getStudents() { | |
| const students = localStorage.getItem(DB_KEYS.STUDENTS); | |
| return students ? JSON.parse(students) : []; | |
| }, | |
| saveStudents(students) { | |
| localStorage.setItem(DB_KEYS.STUDENTS, JSON.stringify(students)); | |
| }, | |
| getEvaluations() { | |
| const evaluations = localStorage.getItem(DB_KEYS.EVALUATIONS); | |
| return evaluations ? JSON.parse(evaluations) : []; | |
| }, | |
| saveEvaluations(evaluations) { | |
| localStorage.setItem(DB_KEYS.EVALUATIONS, JSON.stringify(evaluations)); | |
| }, | |
| teacher: { | |
| username: 'Shaimaa Robaa', | |
| password: 'controlpanel' | |
| } | |
| }; | |
| // Current user | |
| let currentUser = null; | |
| // DOM Elements | |
| const loginScreen = document.getElementById('login-screen'); | |
| const studentDashboard = document.getElementById('student-dashboard'); | |
| const teacherDashboard = document.getElementById('teacher-dashboard'); | |
| const loginForm = document.getElementById('login-form'); | |
| const logoutBtn = document.getElementById('logout-btn'); | |
| const teacherLogoutBtn = document.getElementById('teacher-logout-btn'); | |
| const loginError = document.getElementById('login-error'); | |
| const errorMessage = document.getElementById('error-message'); | |
| const evaluationsContainer = document.getElementById('evaluations-container'); | |
| const noEvaluations = document.getElementById('no-evaluations'); | |
| const studentName = document.getElementById('student-name'); | |
| const studentId = document.getElementById('student-id'); | |
| // Teacher dashboard elements | |
| const manageStudentsTab = document.getElementById('manage-students-tab'); | |
| const uploadEvaluationsTab = document.getElementById('upload-evaluations-tab'); | |
| const manageStudentsPanel = document.getElementById('manage-students-panel'); | |
| const uploadEvaluationsPanel = document.getElementById('upload-evaluations-panel'); | |
| const addStudentForm = document.getElementById('add-student-form'); | |
| const studentList = document.getElementById('student-list'); | |
| const noStudents = document.getElementById('no-students'); | |
| const uploadEvaluationForm = document.getElementById('upload-evaluation-form'); | |
| const teacherEvaluationsContainer = document.getElementById('teacher-evaluations-container'); | |
| const noTeacherEvaluations = document.getElementById('no-teacher-evaluations'); | |
| // Event Listeners | |
| loginForm.addEventListener('submit', handleLogin); | |
| logoutBtn.addEventListener('click', handleLogout); | |
| teacherLogoutBtn.addEventListener('click', handleLogout); | |
| manageStudentsTab.addEventListener('click', () => switchTeacherTab('manage')); | |
| uploadEvaluationsTab.addEventListener('click', () => switchTeacherTab('upload')); | |
| addStudentForm.addEventListener('submit', handleAddStudent); | |
| uploadEvaluationForm.addEventListener('submit', handleUploadEvaluation); | |
| // Initialize the app | |
| function init() { | |
| initializeDatabase(); | |
| // Check if user is already logged in (from session storage) | |
| const storedUser = sessionStorage.getItem('currentUser'); | |
| if (storedUser) { | |
| currentUser = JSON.parse(storedUser); | |
| if (currentUser.username === database.teacher.username) { | |
| showTeacherDashboard(); | |
| loadStudents(); | |
| loadTeacherEvaluations(); | |
| } else { | |
| showStudentDashboard(); | |
| loadStudentEvaluations(); | |
| } | |
| } else { | |
| showLoginScreen(); | |
| } | |
| } | |
| // Handle login | |
| function handleLogin(e) { | |
| e.preventDefault(); | |
| const username = document.getElementById('username').value; | |
| const password = document.getElementById('password').value; | |
| // Check if teacher is logging in | |
| if (username === database.teacher.username && password === database.teacher.password) { | |
| currentUser = { username: database.teacher.username, role: 'teacher' }; | |
| sessionStorage.setItem('currentUser', JSON.stringify(currentUser)); | |
| showTeacherDashboard(); | |
| loadStudents(); | |
| loadTeacherEvaluations(); | |
| return; | |
| } | |
| // Check if student is logging in | |
| const students = database.getStudents(); | |
| const student = students.find(s => s.username === username && s.password === password); | |
| if (student) { | |
| currentUser = { | |
| username: student.username, | |
| id: student.id, | |
| name: student.name, | |
| email: student.email, | |
| role: 'student' | |
| }; | |
| sessionStorage.setItem('currentUser', JSON.stringify(currentUser)); | |
| showStudentDashboard(); | |
| loadStudentEvaluations(); | |
| return; | |
| } | |
| // Invalid credentials | |
| showLoginError(); | |
| } | |
| // Show login error | |
| function showLoginError() { | |
| loginError.classList.remove('hidden'); | |
| loginForm.classList.add('shake'); | |
| setTimeout(() => { | |
| loginForm.classList.remove('shake'); | |
| }, 500); | |
| } | |
| // Handle logout | |
| function handleLogout() { | |
| currentUser = null; | |
| sessionStorage.removeItem('currentUser'); | |
| showLoginScreen(); | |
| loginForm.reset(); | |
| } | |
| // Show login screen | |
| function showLoginScreen() { | |
| loginScreen.classList.remove('hidden'); | |
| studentDashboard.classList.add('hidden'); | |
| teacherDashboard.classList.add('hidden'); | |
| loginError.classList.add('hidden'); | |
| } | |
| // Show student dashboard | |
| function showStudentDashboard() { | |
| loginScreen.classList.add('hidden'); | |
| studentDashboard.classList.remove('hidden'); | |
| teacherDashboard.classList.add('hidden'); | |
| // Set student info | |
| studentName.textContent = currentUser.name; | |
| studentId.textContent = currentUser.id; | |
| } | |
| // Show teacher dashboard | |
| function showTeacherDashboard() { | |
| loginScreen.classList.add('hidden'); | |
| studentDashboard.classList.add('hidden'); | |
| teacherDashboard.classList.remove('hidden'); | |
| } | |
| // Load student evaluations | |
| function loadStudentEvaluations() { | |
| const studentEvaluations = database.getEvaluations().filter(eval => | |
| eval.assignedTo.includes(currentUser.id) | |
| ); | |
| evaluationsContainer.innerHTML = ''; | |
| if (studentEvaluations.length === 0) { | |
| noEvaluations.classList.remove('hidden'); | |
| return; | |
| } | |
| noEvaluations.classList.add('hidden'); | |
| studentEvaluations.forEach(eval => { | |
| const status = eval.status[currentUser.id] || 'Pending'; | |
| const statusColor = getStatusColor(status); | |
| const evalCard = document.createElement('div'); | |
| evalCard.className = 'evaluation-card bg-white rounded-lg shadow p-6'; | |
| evalCard.innerHTML = ` | |
| <div class="flex justify-between items-start"> | |
| <div> | |
| <h3 class="text-lg font-semibold text-gray-800">${eval.title}</h3> | |
| <p class="text-gray-600 mt-1">${eval.description}</p> | |
| </div> | |
| <span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium ${statusColor}"> | |
| ${status} | |
| </span> | |
| </div> | |
| <div class="mt-4 flex items-center text-sm text-gray-500"> | |
| <i class="far fa-calendar-alt mr-2"></i> | |
| Due: ${formatDate(eval.date)} | |
| </div> | |
| <div class="mt-4"> | |
| <a href="#" class="inline-flex items-center text-indigo-600 hover:text-indigo-800"> | |
| <i class="far fa-file-pdf mr-2"></i> Download Evaluation | |
| </a> | |
| </div> | |
| ${status === 'Pending' ? ` | |
| <div class="mt-4"> | |
| <button class="w-full inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> | |
| Submit Solution | |
| </button> | |
| </div> | |
| ` : ''} | |
| `; | |
| evaluationsContainer.appendChild(evalCard); | |
| }); | |
| } | |
| // Load students for teacher dashboard | |
| function loadStudents() { | |
| studentList.innerHTML = ''; | |
| const students = database.getStudents(); | |
| if (students.length === 0) { | |
| noStudents.classList.remove('hidden'); | |
| return; | |
| } | |
| noStudents.classList.add('hidden'); | |
| students.forEach(student => { | |
| const studentRow = document.createElement('tr'); | |
| studentRow.innerHTML = ` | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="flex items-center"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-indigo-100 flex items-center justify-center"> | |
| <i class="fas fa-user text-indigo-600"></i> | |
| </div> | |
| <div class="ml-4"> | |
| <div class="text-sm font-medium text-gray-900">${student.name}</div> | |
| <div class="text-sm text-gray-500">${student.id}</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm text-gray-900">${student.username}</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm text-gray-900">${student.email}</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | |
| <button class="text-indigo-600 hover:text-indigo-900 mr-3 edit-student" data-id="${student.id}"> | |
| <i class="fas fa-edit"></i> | |
| </button> | |
| <button class="text-red-600 hover:text-red-900 delete-student" data-id="${student.id}"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </td> | |
| `; | |
| studentList.appendChild(studentRow); | |
| }); | |
| // Add event listeners to edit and delete buttons | |
| document.querySelectorAll('.edit-student').forEach(btn => { | |
| btn.addEventListener('click', (e) => { | |
| const studentId = e.currentTarget.getAttribute('data-id'); | |
| editStudent(studentId); | |
| }); | |
| }); | |
| document.querySelectorAll('.delete-student').forEach(btn => { | |
| btn.addEventListener('click', (e) => { | |
| const studentId = e.currentTarget.getAttribute('data-id'); | |
| deleteStudent(studentId); | |
| }); | |
| }); | |
| } | |
| // Load teacher evaluations | |
| function loadTeacherEvaluations() { | |
| teacherEvaluationsContainer.innerHTML = ''; | |
| const evaluations = database.getEvaluations(); | |
| if (evaluations.length === 0) { | |
| noTeacherEvaluations.classList.remove('hidden'); | |
| return; | |
| } | |
| noTeacherEvaluations.classList.add('hidden'); | |
| evaluations.forEach(eval => { | |
| const students = database.getStudents(); | |
| const assignedStudents = eval.assignedTo.map(id => { | |
| const student = students.find(s => s.id === id); | |
| return student ? student.name : ''; | |
| }).filter(name => name !== ''); | |
| const submittedCount = Object.values(eval.status).filter(s => s === 'Submitted').length; | |
| const totalCount = eval.assignedTo.length; | |
| const evalCard = document.createElement('div'); | |
| evalCard.className = 'evaluation-card bg-white rounded-lg shadow p-6'; | |
| evalCard.innerHTML = ` | |
| <div class="flex justify-between items-start"> | |
| <div> | |
| <h3 class="text-lg font-semibold text-gray-800">${eval.title}</h3> | |
| <p class="text-gray-600 mt-1">${eval.description}</p> | |
| </div> | |
| <span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800"> | |
| ${submittedCount}/${totalCount} submitted | |
| </span> | |
| </div> | |
| <div class="mt-4 flex items-center text-sm text-gray-500"> | |
| <i class="far fa-calendar-alt mr-2"></i> | |
| Due: ${formatDate(eval.date)} | |
| </div> | |
| <div class="mt-3"> | |
| <span class="text-sm text-gray-600">Assigned to:</span> | |
| <div class="mt-1 flex flex-wrap gap-2"> | |
| ${assignedStudents.map(name => ` | |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800"> | |
| ${name} | |
| </span> | |
| `).join('')} | |
| </div> | |
| </div> | |
| <div class="mt-4 flex space-x-3"> | |
| <a href="#" class="inline-flex items-center text-indigo-600 hover:text-indigo-800"> | |
| <i class="far fa-file-pdf mr-2"></i> Download | |
| </a> | |
| <a href="#" class="inline-flex items-center text-gray-600 hover:text-gray-800"> | |
| <i class="fas fa-list-check mr-2"></i> View Submissions | |
| </a> | |
| <a href="#" class="inline-flex items-center text-gray-600 hover:text-gray-800"> | |
| <i class="fas fa-edit mr-2"></i> Edit | |
| </a> | |
| </div> | |
| `; | |
| teacherEvaluationsContainer.appendChild(evalCard); | |
| }); | |
| } | |
| // Switch between teacher tabs | |
| function switchTeacherTab(tab) { | |
| if (tab === 'manage') { | |
| manageStudentsTab.classList.remove('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300'); | |
| manageStudentsTab.classList.add('border-indigo-500', 'text-indigo-600'); | |
| uploadEvaluationsTab.classList.remove('border-indigo-500', 'text-indigo-600'); | |
| uploadEvaluationsTab.classList.add('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300'); | |
| manageStudentsPanel.classList.remove('hidden'); | |
| uploadEvaluationsPanel.classList.add('hidden'); | |
| } else { | |
| uploadEvaluationsTab.classList.remove('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300'); | |
| uploadEvaluationsTab.classList.add('border-indigo-500', 'text-indigo-600'); | |
| manageStudentsTab.classList.remove('border-indigo-500', 'text-indigo-600'); | |
| manageStudentsTab.classList.add('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300'); | |
| uploadEvaluationsPanel.classList.remove('hidden'); | |
| manageStudentsPanel.classList.add('hidden'); | |
| } | |
| } | |
| // Handle add student | |
| function handleAddStudent(e) { | |
| e.preventDefault(); | |
| const firstname = document.getElementById('student-firstname').value; | |
| const lastname = document.getElementById('student-lastname').value; | |
| const email = document.getElementById('student-email').value; | |
| const username = document.getElementById('student-username').value; | |
| const password = document.getElementById('student-password').value; | |
| // Generate student ID | |
| const students = database.getStudents(); | |
| const id = 'S' + (1000 + students.length + 1); | |
| // Create new student | |
| const newStudent = { | |
| id, | |
| username, | |
| password, | |
| name: `${firstname} ${lastname}`, | |
| }; | |
| // Add to database | |
| students.push(newStudent); | |
| database.saveStudents(students); | |
| // Reload students | |
| loadStudents(); | |
| // Reset form | |
| addStudentForm.reset(); | |
| // Show success message | |
| showAlert('Student added successfully!', 'success'); | |
| } | |
| // Edit student | |
| function editStudent(studentId) { | |
| const students = database.getStudents(); | |
| const student = students.find(s => s.id === studentId); | |
| if (student) { | |
| // In a real app, you would show a modal or form to edit the student | |
| // For this demo, we'll just show a prompt for each field | |
| const newName = prompt('Edit student name:', student.name); | |
| if (newName !== null) { | |
| student.name = newName; | |
| const newUsername = prompt('Edit username:', student.username); | |
| if (newUsername !== null) student.username = newUsername; | |
| const newEmail = prompt('Edit email:', student.email); | |
| if (newEmail !== null) student.email = newEmail; | |
| // Save changes | |
| database.saveStudents(students); | |
| loadStudents(); | |
| showAlert('Student updated successfully!', 'success'); | |
| } | |
| } | |
| } | |
| // Delete student | |
| function deleteStudent(studentId) { | |
| if (confirm('Are you sure you want to delete this student?')) { | |
| const students = database.getStudents(); | |
| const index = students.findIndex(s => s.id === studentId); | |
| if (index !== -1) { | |
| students.splice(index, 1); | |
| database.saveStudents(students); | |
| loadStudents(); | |
| showAlert('Student deleted successfully!', 'success'); | |
| } | |
| } | |
| } | |
| // Handle upload evaluation | |
| function handleUploadEvaluation(e) { | |
| e.preventDefault(); | |
| const title = document.getElementById('evaluation-title').value; | |
| const description = document.getElementById('evaluation-description').value; | |
| const date = document.getElementById('evaluation-date').value; | |
| // In a real app, you would handle file upload here | |
| const fileInput = document.getElementById('file-upload'); | |
| const fileName = fileInput.files.length > 0 ? fileInput.files[0].name : 'evaluation.pdf'; | |
| // Generate evaluation ID | |
| const evaluations = database.getEvaluations(); | |
| const id = 'E' + (100 + evaluations.length + 1); | |
| // Get all student IDs | |
| const students = database.getStudents(); | |
| const assignedTo = students.map(s => s.id); | |
| // Create status object with all students as pending | |
| const status = {}; | |
| assignedTo.forEach(id => { | |
| status[id] = 'Pending'; | |
| }); | |
| // Create new evaluation | |
| const newEvaluation = { | |
| id, | |
| title, | |
| description, | |
| date, | |
| file: fileName, | |
| assignedTo, | |
| status | |
| }; | |
| // Add to database | |
| evaluations.push(newEvaluation); | |
| database.saveEvaluations(evaluations); | |
| // Reload evaluations | |
| loadTeacherEvaluations(); | |
| // Reset form | |
| uploadEvaluationForm.reset(); | |
| // Show success message | |
| showAlert('Evaluation uploaded successfully!', 'success'); | |
| } | |
| // Show alert message | |
| function showAlert(message, type) { | |
| const alertDiv = document.createElement('div'); | |
| alertDiv.className = `fixed top-4 right-4 px-4 py-3 rounded shadow-lg ${type === 'success' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`; | |
| alertDiv.innerHTML = ` | |
| <div class="flex items-center"> | |
| <i class="fas ${type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle'} mr-2"></i> | |
| <span>${message}</span> | |
| </div> | |
| `; | |
| document.body.appendChild(alertDiv); | |
| setTimeout(() => { | |
| alertDiv.classList.add('opacity-0', 'transition-opacity', 'duration-500'); | |
| setTimeout(() => { | |
| alertDiv.remove(); | |
| }, 500); | |
| }, 3000); | |
| } | |
| // Helper functions | |
| function formatDate(dateString) { | |
| const options = { year: 'numeric', month: 'long', day: 'numeric' }; | |
| return new Date(dateString).toLocaleDateString(undefined, options); | |
| } | |
| function getStatusColor(status) { | |
| if (status === 'Submitted') return 'bg-green-100 text-green-800'; | |
| if (status === 'Pending') return 'bg-yellow-100 text-yellow-800'; | |
| if (status === 'Late') return 'bg-red-100 text-red-800'; | |
| return 'bg-gray-100 text-gray-800'; | |
| } | |
| // Initialize the app | |
| init(); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ABSONUMBER1/evaluation" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |