| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Student Management 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> |
| .modal { |
| transition: opacity 0.25s ease; |
| } |
| body.modal-active { |
| overflow-x: hidden; |
| overflow-y: visible !important; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100"> |
| <div class="container mx-auto px-4 py-8"> |
| |
| <header class="flex justify-between items-center mb-8"> |
| <h1 class="text-3xl font-bold text-indigo-700"> |
| <i class="fas fa-graduation-cap mr-2"></i>Student Management |
| </h1> |
| <button id="addStudentBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg transition duration-200"> |
| <i class="fas fa-plus mr-2"></i>Add New Student |
| </button> |
| </header> |
|
|
| |
| <div class="bg-white p-4 rounded-lg shadow-md mb-6"> |
| <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4"> |
| <div class="relative w-full md:w-96"> |
| <input type="text" id="searchInput" placeholder="Search students..." |
| class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> |
| </div> |
| <div class="flex items-center space-x-4"> |
| <div> |
| <label for="filterYear" class="block text-sm font-medium text-gray-700 mb-1">Year</label> |
| <select id="filterYear" class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="">All Years</option> |
| <option value="1">1st Year</option> |
| <option value="2">2nd Year</option> |
| <option value="3">3rd Year</option> |
| <option value="4">4th Year</option> |
| </select> |
| </div> |
| <div> |
| <label for="filterCourse" class="block text-sm font-medium text-gray-700 mb-1">Course</label> |
| <select id="filterCourse" class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="">All Courses</option> |
| <option value="Computer Science">Computer Science</option> |
| <option value="Engineering">Engineering</option> |
| <option value="Business">Business</option> |
| <option value="Medicine">Medicine</option> |
| </select> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-lg shadow-md overflow-hidden"> |
| <div class="overflow-x-auto"> |
| <table class="min-w-full divide-y divide-gray-200"> |
| <thead class="bg-gray-50"> |
| <tr> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Course</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Year</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> |
| </tr> |
| </thead> |
| <tbody id="studentTableBody" class="bg-white divide-y divide-gray-200"> |
| |
| <tr> |
| <td colspan="6" class="px-6 py-4 text-center text-gray-500">Loading student data...</td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="px-6 py-4 border-t border-gray-200 flex items-center justify-between"> |
| <div class="text-sm text-gray-500"> |
| Showing <span id="startRow">1</span> to <span id="endRow">10</span> of <span id="totalRows">100</span> entries |
| </div> |
| <div class="flex space-x-1"> |
| <button id="prevPage" class="px-3 py-1 border rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200"> |
| <i class="fas fa-chevron-left"></i> |
| </button> |
| <button class="px-3 py-1 border rounded-lg bg-indigo-600 text-white">1</button> |
| <button class="px-3 py-1 border rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200">2</button> |
| <button class="px-3 py-1 border rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200">3</button> |
| <button id="nextPage" class="px-3 py-1 border rounded-lg bg-gray-100 text-gray-700 hover:bg-gray-200"> |
| <i class="fas fa-chevron-right"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="studentModal" class="fixed z-50 inset-0 overflow-y-auto hidden" aria-labelledby="modal-title" role="dialog" aria-modal="true"> |
| <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
| <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div> |
| <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span> |
| <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"> |
| <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |
| <div class="flex justify-between items-start"> |
| <h3 class="text-lg leading-6 font-medium text-gray-900" id="modalTitle"> |
| Add New Student |
| </h3> |
| <button id="closeModalBtn" class="text-gray-400 hover:text-gray-500"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="mt-4"> |
| <form id="studentForm"> |
| <input type="hidden" id="studentId"> |
| <div class="mb-4"> |
| <label for="name" class="block text-sm font-medium text-gray-700 mb-1">Full Name</label> |
| <input type="text" id="name" name="name" required |
| class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| </div> |
| <div class="mb-4"> |
| <label for="email" class="block text-sm font-medium text-gray-700 mb-1">Email</label> |
| <input type="email" id="email" name="email" required |
| class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| </div> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"> |
| <div> |
| <label for="course" class="block text-sm font-medium text-gray-700 mb-1">Course</label> |
| <select id="course" name="course" required |
| class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="">Select Course</option> |
| <option value="Computer Science">Computer Science</option> |
| <option value="Engineering">Engineering</option> |
| <option value="Business">Business</option> |
| <option value="Medicine">Medicine</option> |
| <option value="Arts">Arts</option> |
| <option value="Science">Science</option> |
| </select> |
| </div> |
| <div> |
| <label for="year" class="block text-sm font-medium text-gray-700 mb-1">Year Level</label> |
| <select id="year" name="year" required |
| class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| <option value="">Select Year</option> |
| <option value="1">1st Year</option> |
| <option value="2">2nd Year</option> |
| <option value="3">3rd Year</option> |
| <option value="4">4th Year</option> |
| </select> |
| </div> |
| </div> |
| <div class="mb-4"> |
| <label for="address" class="block text-sm font-medium text-gray-700 mb-1">Address</label> |
| <textarea id="address" name="address" rows="3" |
| class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"></textarea> |
| </div> |
| <div class="mb-4"> |
| <label for="phone" class="block text-sm font-medium text-gray-700 mb-1">Phone Number</label> |
| <input type="tel" id="phone" name="phone" |
| class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
| </div> |
| </form> |
| </div> |
| </div> |
| <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |
| <button type="button" id="saveStudentBtn" |
| class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm"> |
| Save |
| </button> |
| <button type="button" id="cancelBtn" |
| class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> |
| Cancel |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="confirmModal" class="fixed z-50 inset-0 overflow-y-auto hidden"> |
| <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
| <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div> |
| <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span> |
| <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"> |
| <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |
| <div class="sm:flex sm:items-start"> |
| <div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"> |
| <i class="fas fa-exclamation text-red-600"></i> |
| </div> |
| <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |
| <h3 class="text-lg leading-6 font-medium text-gray-900" id="confirmModalTitle">Delete Student</h3> |
| <div class="mt-2"> |
| <p class="text-sm text-gray-500" id="confirmModalMessage">Are you sure you want to delete this student? This action cannot be undone.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |
| <button type="button" id="confirmDeleteBtn" |
| class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"> |
| Delete |
| </button> |
| <button type="button" id="cancelDeleteBtn" |
| class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> |
| Cancel |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const dbConfig = { |
| host: 'localhost', |
| user: 'root', |
| password: '', |
| database: 'student' |
| }; |
| |
| |
| let currentPage = 1; |
| let studentsPerPage = 10; |
| let allStudents = []; |
| let currentAction = 'add'; |
| let studentToDelete = null; |
| |
| |
| const studentModal = document.getElementById('studentModal'); |
| const confirmModal = document.getElementById('confirmModal'); |
| const studentTableBody = document.getElementById('studentTableBody'); |
| const searchInput = document.getElementById('searchInput'); |
| const filterYear = document.getElementById('filterYear'); |
| const filterCourse = document.getElementById('filterCourse'); |
| |
| |
| document.getElementById('addStudentBtn').addEventListener('click', () => { |
| currentAction = 'add'; |
| document.getElementById('modalTitle').textContent = 'Add New Student'; |
| document.getElementById('studentForm').reset(); |
| document.getElementById('studentId').value = ''; |
| studentModal.classList.remove('hidden'); |
| }); |
| |
| document.getElementById('closeModalBtn').addEventListener('click', () => { |
| studentModal.classList.add('hidden'); |
| }); |
| |
| document.getElementById('cancelBtn').addEventListener('click', () => { |
| studentModal.classList.add('hidden'); |
| }); |
| |
| document.getElementById('saveStudentBtn').addEventListener('click', saveStudent); |
| document.getElementById('confirmDeleteBtn').addEventListener('click', deleteStudent); |
| document.getElementById('cancelDeleteBtn').addEventListener('click', () => { |
| confirmModal.classList.add('hidden'); |
| }); |
| |
| searchInput.addEventListener('input', filterStudents); |
| filterYear.addEventListener('change', filterStudents); |
| filterCourse.addEventListener('change', filterStudents); |
| document.getElementById('prevPage').addEventListener('click', () => { |
| if (currentPage > 1) { |
| currentPage--; |
| displayStudents(); |
| } |
| }); |
| document.getElementById('nextPage').addEventListener('click', () => { |
| if (currentPage < Math.ceil(allStudents.length / studentsPerPage)) { |
| currentPage++; |
| displayStudents(); |
| } |
| }); |
| |
| |
| document.addEventListener('DOMContentLoaded', () => { |
| |
| |
| mockDatabaseConnection(); |
| displayStudents(); |
| }); |
| |
| |
| function mockDatabaseConnection() { |
| console.log(`Connecting to MySQL database at ${dbConfig.host}...`); |
| |
| |
| allStudents = [ |
| { id: 1, name: 'John Doe', email: 'john@example.com', course: 'Computer Science', year: 2, address: '123 Main St', phone: '555-1234' }, |
| { id: 2, name: 'Jane Smith', email: 'jane@example.com', course: 'Engineering', year: 3, address: '456 Oak Ave', phone: '555-5678' }, |
| { id: 3, name: 'Michael Johnson', email: 'michael@example.com', course: 'Business', year: 1, address: '789 Pine Rd', phone: '555-9012' }, |
| { id: 4, name: 'Emily Davis', email: 'emily@example.com', course: 'Medicine', year: 4, address: '321 Elm Blvd', phone: '555-3456' }, |
| { id: 5, name: 'Robert Wilson', email: 'robert@example.com', course: 'Computer Science', year: 2, address: '654 Maple Ln', phone: '555-7890' }, |
| { id: 6, name: 'Sarah Thompson', email: 'sarah@example.com', course: 'Engineering', year: 3, address: '987 Cedar Ct', phone: '555-2345' }, |
| { id: 7, name: 'David Lee', email: 'david@example.com', course: 'Arts', year: 1, address: '135 Birch Way', phone: '555-6789' }, |
| { id: 8, name: 'Jennifer Brown', email: 'jennifer@example.com', course: 'Science', year: 4, address: '864 Willow Dr', phone: '555-0123' }, |
| { id: 9, name: 'Daniel Taylor', email: 'daniel@example.com', course: 'Computer Science', year: 2, address: '246 Spruce St', phone: '555-4567' }, |
| { id: 10, name: 'Amanda Martinez', email: 'amanda@example.com', course: 'Business', year: 3, address: '579 Ash Ave', phone: '555-8901' }, |
| { id: 11, name: 'Christopher Anderson', email: 'chris@example.com', course: 'Medicine', year: 1, address: '912 Oakwood Ln', phone: '555-2345' }, |
| { id: 12, name: 'Jessica Garcia', email: 'jessica@example.com', course: 'Engineering', year: 4, address: '753 Pinecrest Dr', phone: '555-6789' } |
| ]; |
| |
| console.log('Successfully retrieved student data from database'); |
| } |
| |
| |
| function displayStudents() { |
| const filteredStudents = getFilteredStudents(); |
| const startIndex = (currentPage - 1) * studentsPerPage; |
| const endIndex = Math.min(startIndex + studentsPerPage, filteredStudents.length); |
| const paginatedStudents = filteredStudents.slice(startIndex, endIndex); |
| |
| let tableHTML = ''; |
| |
| if (paginatedStudents.length === 0) { |
| tableHTML = `<tr> |
| <td colspan="6" class="px-6 py-4 text-center text-gray-500">No students found matching your criteria</td> |
| </tr>`; |
| } else { |
| paginatedStudents.forEach(student => { |
| tableHTML += ` |
| <tr class="hover:bg-gray-50"> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${student.id}</td> |
| <td class="px-6 py-4 whitespace-nowrap"> |
| <div class="text-sm font-medium text-gray-900">${student.name}</div> |
| </td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${student.email}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${student.course}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${student.year}${getOrdinalSuffix(student.year)} Year</td> |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |
| <button onclick="editStudent(${student.id})" class="text-indigo-600 hover:text-indigo-900 mr-4"> |
| <i class="fas fa-edit mr-1"></i>Edit |
| </button> |
| <button onclick="confirmDelete(${student.id})" class="text-red-600 hover:text-red-900"> |
| <i class="fas fa-trash mr-1"></i>Delete |
| </button> |
| </td> |
| </tr> |
| `; |
| }); |
| } |
| |
| studentTableBody.innerHTML = tableHTML; |
| |
| |
| document.getElementById('startRow').textContent = startIndex + 1; |
| document.getElementById('endRow').textContent = endIndex; |
| document.getElementById('totalRows').textContent = filteredStudents.length; |
| |
| |
| document.getElementById('prevPage').disabled = currentPage === 1; |
| document.getElementById('nextPage').disabled = endIndex >= filteredStudents.length; |
| } |
| |
| |
| function getFilteredStudents() { |
| const searchTerm = searchInput.value.toLowerCase(); |
| const yearFilter = filterYear.value; |
| const courseFilter = filterCourse.value; |
| |
| return allStudents.filter(student => { |
| const matchesSearch = student.name.toLowerCase().includes(searchTerm) || |
| student.email.toLowerCase().includes(searchTerm) || |
| student.course.toLowerCase().includes(searchTerm); |
| const matchesYear = !yearFilter || student.year == yearFilter; |
| const matchesCourse = !courseFilter || student.course === courseFilter; |
| |
| return matchesSearch && matchesYear && matchesCourse; |
| }); |
| } |
| |
| |
| function filterStudents() { |
| currentPage = 1; |
| displayStudents(); |
| } |
| |
| |
| function saveStudent() { |
| const id = document.getElementById('studentId').value; |
| const name = document.getElementById('name').value; |
| const email = document.getElementById('email').value; |
| const course = document.getElementById('course').value; |
| const year = document.getElementById('year').value; |
| const address = document.getElementById('address').value; |
| const phone = document.getElementById('phone').value; |
| |
| if (!name || !email || !course || !year) { |
| alert('Please fill in all required fields'); |
| return; |
| } |
| |
| |
| if (currentAction === 'add') { |
| |
| const newId = allStudents.length > 0 ? Math.max(...allStudents.map(s => s.id)) + 1 : 1; |
| const newStudent = { |
| id: newId, |
| name, |
| email, |
| course, |
| year, |
| address, |
| phone |
| }; |
| allStudents.push(newStudent); |
| console.log('Adding new student to database:', newStudent); |
| } else { |
| |
| const index = allStudents.findIndex(s => s.id == id); |
| if (index !== -1) { |
| allStudents[index] = { |
| id: parseInt(id), |
| name, |
| email, |
| course, |
| year, |
| address, |
| phone |
| }; |
| console.log('Updating student in database:', allStudents[index]); |
| } |
| } |
| |
| |
| studentModal.classList.add('hidden'); |
| displayStudents(); |
| } |
| |
| |
| function editStudent(id) { |
| currentAction = 'edit'; |
| document.getElementById('modalTitle').textContent = 'Edit Student'; |
| |
| const student = allStudents.find(s => s.id === id); |
| if (student) { |
| document.getElementById('studentId').value = student.id; |
| document.getElementById('name').value = student.name; |
| document.getElementById('email').value = student.email; |
| document.getElementById('course').value = student.course; |
| document.getElementById('year').value = student.year; |
| document.getElementById('address').value = student.address || ''; |
| document.getElementById('phone').value = student.phone || ''; |
| |
| studentModal.classList.remove('hidden'); |
| } |
| } |
| |
| |
| function confirmDelete(id) { |
| studentToDelete = id; |
| confirmModal.classList.remove('hidden'); |
| } |
| |
| |
| function deleteStudent() { |
| if (studentToDelete) { |
| |
| allStudents = allStudents.filter(s => s.id !== studentToDelete); |
| console.log(`Deleted student with ID ${studentToDelete} from database`); |
| |
| |
| if (currentPage > 1 && allStudents.length <= (currentPage - 1) * studentsPerPage) { |
| currentPage--; |
| } |
| |
| displayStudents(); |
| } |
| |
| confirmModal.classList.add('hidden'); |
| studentToDelete = null; |
| } |
| |
| |
| function getOrdinalSuffix(n) { |
| const s = ["th", "st", "nd", "rd"]; |
| const v = n % 100; |
| return s[(v - 20) % 10] || s[v] || s[0]; |
| } |
| </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=meldeb/crud-app" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> |
| </html> |