| | <!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> |