/** * StudentMS — script.js * Client-side validation, modals, and UI helpers. */ /* ═══════════════════════════════════════════ 1. AUTO-DISMISS FLASH MESSAGES ═══════════════════════════════════════════ */ document.addEventListener('DOMContentLoaded', () => { const alerts = document.querySelectorAll('.alert'); alerts.forEach(alert => { setTimeout(() => { alert.style.transition = 'opacity .4s, transform .4s'; alert.style.opacity = '0'; alert.style.transform = 'translateX(40px)'; setTimeout(() => alert.remove(), 420); }, 4500); }); }); /* ═══════════════════════════════════════════ 2. MOBILE NAVBAR TOGGLE ═══════════════════════════════════════════ */ const navToggle = document.getElementById('navToggle'); const navLinks = document.getElementById('navLinks'); if (navToggle && navLinks) { navToggle.addEventListener('click', () => { navLinks.classList.toggle('open'); }); // Close when clicking outside document.addEventListener('click', (e) => { if (!navToggle.contains(e.target) && !navLinks.contains(e.target)) { navLinks.classList.remove('open'); } }); } /* ═══════════════════════════════════════════ 3. PASSWORD TOGGLE ═══════════════════════════════════════════ */ function togglePassword(inputId, btn) { const input = document.getElementById(inputId); const icon = btn.querySelector('i'); if (input.type === 'password') { input.type = 'text'; icon.classList.replace('fa-eye', 'fa-eye-slash'); } else { input.type = 'password'; icon.classList.replace('fa-eye-slash', 'fa-eye'); } } /* ═══════════════════════════════════════════ 4. LOGIN FORM VALIDATION ═══════════════════════════════════════════ */ const loginForm = document.getElementById('loginForm'); if (loginForm) { loginForm.addEventListener('submit', (e) => { let valid = true; const username = document.getElementById('username'); const password = document.getElementById('password'); const errUser = document.getElementById('err-username'); const errPass = document.getElementById('err-password'); // Reset [errUser, errPass].forEach(el => { if (el) el.textContent = ''; }); [username, password].forEach(el => el.classList.remove('is-invalid')); if (!username.value.trim()) { errUser.textContent = 'Username is required.'; username.classList.add('is-invalid'); valid = false; } if (!password.value.trim()) { errPass.textContent = 'Password is required.'; password.classList.add('is-invalid'); valid = false; } if (!valid) e.preventDefault(); }); } /* ═══════════════════════════════════════════ 5. STUDENT FORM VALIDATION (add & edit) ═══════════════════════════════════════════ */ const studentForm = document.getElementById('studentForm'); if (studentForm) { studentForm.addEventListener('submit', (e) => { const errors = validateStudentForm(); if (errors > 0) e.preventDefault(); }); } function validateStudentForm() { let errorCount = 0; // Helper: show error function showErr(fieldName, msg) { const errEl = document.getElementById(`err-${fieldName}`); const input = studentForm.querySelector(`[name="${fieldName}"]`); if (errEl) errEl.textContent = msg; if (input) input.classList.add('is-invalid'); errorCount++; } // Helper: clear error function clearErr(fieldName) { const errEl = document.getElementById(`err-${fieldName}`); const input = studentForm.querySelector(`[name="${fieldName}"]`); if (errEl) errEl.textContent = ''; if (input) input.classList.remove('is-invalid'); } // Fields to validate const required = [ 'student_id', 'full_name', 'father_name', 'mother_name', 'gender', 'dob', 'email', 'phone', 'course', 'branch', 'year_sem', 'address', 'city', 'state', 'pin_code' ]; required.forEach(name => clearErr(name)); // Required check required.forEach(name => { const el = studentForm.querySelector(`[name="${name}"]`); if (!el) return; if (!el.value.trim()) { const label = name.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); showErr(name, `${label} is required.`); } }); // Email format const emailEl = studentForm.querySelector('[name="email"]'); if (emailEl && emailEl.value.trim()) { const re = /^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$/; if (!re.test(emailEl.value.trim())) { showErr('email', 'Enter a valid email address.'); } } // Phone — 10 digits only const phoneEl = studentForm.querySelector('[name="phone"]'); if (phoneEl && phoneEl.value.trim()) { if (!/^\d{10}$/.test(phoneEl.value.trim())) { showErr('phone', 'Phone must be exactly 10 digits.'); } } // Pin code — 6 digits only const pinEl = studentForm.querySelector('[name="pin_code"]'); if (pinEl && pinEl.value.trim()) { if (!/^\d{6}$/.test(pinEl.value.trim())) { showErr('pin_code', 'Pin Code must be exactly 6 digits.'); } } // Date of birth — must not be in the future const dobEl = studentForm.querySelector('[name="dob"]'); if (dobEl && dobEl.value) { const dob = new Date(dobEl.value); if (dob >= new Date()) { showErr('dob', 'Date of Birth cannot be in the future.'); } } return errorCount; } // Live phone & pin – allow only digits document.addEventListener('DOMContentLoaded', () => { const phoneInput = document.querySelector('[name="phone"]'); const pinInput = document.querySelector('[name="pin_code"]'); if (phoneInput) { phoneInput.addEventListener('input', () => { phoneInput.value = phoneInput.value.replace(/\D/g, '').slice(0, 10); }); } if (pinInput) { pinInput.addEventListener('input', () => { pinInput.value = pinInput.value.replace(/\D/g, '').slice(0, 6); }); } }); /* ═══════════════════════════════════════════ 6. DELETE MODAL ═══════════════════════════════════════════ */ let pendingDeleteId = null; function confirmDelete(studentId, studentName) { pendingDeleteId = studentId; const modal = document.getElementById('deleteModal'); const nameEl = document.getElementById('deleteStudentName'); if (nameEl) nameEl.textContent = studentName; if (modal) modal.style.display = 'flex'; } function closeModal() { const modal = document.getElementById('deleteModal'); if (modal) modal.style.display = 'none'; pendingDeleteId = null; } function submitDelete() { if (!pendingDeleteId) return; const form = document.getElementById('deleteForm'); if (form) { form.action = `/delete_student/${pendingDeleteId}`; form.submit(); } } // Close modal when clicking backdrop document.addEventListener('click', (e) => { const modal = document.getElementById('deleteModal'); if (modal && e.target === modal) closeModal(); }); // Close modal on Escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeModal(); }); /* ═══════════════════════════════════════════ 7. SEARCH – CLEAR ═══════════════════════════════════════════ */ function clearSearch() { const input = document.getElementById('searchInput'); if (input) { input.value = ''; document.getElementById('searchForm').submit(); } }