crud-app / index.html
meldeb's picture
Add 2 files
34edd4a verified
<!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 -->
<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>
<!-- Search and Filter -->
<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>
<!-- Student Table -->
<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">
<!-- Student data will be loaded here via PHP/JavaScript -->
<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>
<!-- Add/Edit Student Modal -->
<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">&#8203;</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>
<!-- Confirmation Modal -->
<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">&#8203;</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>
// Database connection details
const dbConfig = {
host: 'localhost',
user: 'root',
password: '', // XAMPP default has no password
database: 'student'
};
// Global variables
let currentPage = 1;
let studentsPerPage = 10;
let allStudents = [];
let currentAction = 'add';
let studentToDelete = null;
// DOM Elements
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');
// Event Listeners
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();
}
});
// Initialize the application
document.addEventListener('DOMContentLoaded', () => {
// For demonstration, we'll use mock data since we can't actually connect to MySQL directly from frontend
// In a real application, you would use PHP/Node.js backend to connect to MySQL
mockDatabaseConnection();
displayStudents();
});
// Database connection mock (would be replaced with actual backend code in production)
function mockDatabaseConnection() {
console.log(`Connecting to MySQL database at ${dbConfig.host}...`);
// Mock data - in real app this would come from actual MySQL database
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');
}
// Display students in the table
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;
// Update pagination info
document.getElementById('startRow').textContent = startIndex + 1;
document.getElementById('endRow').textContent = endIndex;
document.getElementById('totalRows').textContent = filteredStudents.length;
// Disable/enable pagination buttons
document.getElementById('prevPage').disabled = currentPage === 1;
document.getElementById('nextPage').disabled = endIndex >= filteredStudents.length;
}
// Filter students based on search and filters
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;
});
}
// Apply filters and refresh display
function filterStudents() {
currentPage = 1;
displayStudents();
}
// Save student (add or edit)
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;
}
// In a real app, you would send this to your backend which would then update the MySQL database
if (currentAction === 'add') {
// Add new student
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 {
// Edit existing student
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]);
}
}
// Close modal and refresh display
studentModal.classList.add('hidden');
displayStudents();
}
// Edit student
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');
}
}
// Confirm delete
function confirmDelete(id) {
studentToDelete = id;
confirmModal.classList.remove('hidden');
}
// Delete student
function deleteStudent() {
if (studentToDelete) {
// In a real app, you would send a request to your backend to delete from MySQL
allStudents = allStudents.filter(s => s.id !== studentToDelete);
console.log(`Deleted student with ID ${studentToDelete} from database`);
// Reset current page if needed
if (currentPage > 1 && allStudents.length <= (currentPage - 1) * studentsPerPage) {
currentPage--;
}
displayStudents();
}
confirmModal.classList.add('hidden');
studentToDelete = null;
}
// Helper function for ordinal suffix
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>