Files
2026-02-10 22:11:06 -05:00

108 lines
3.5 KiB
JavaScript

/* modal_validation.js
live client-side checks for each .student-edit-form
─────────────────────────────────────────────── */
document.addEventListener('DOMContentLoaded', () => {
/* basic regex rules */
const nameRE = /^[A-Za-z\s-]{2,30}$/;
const gradeRE = /^[A-Za-z0-9\s-]{1,20}$/;
const MIN_AGE = 5, MAX_AGE = 18;
const calcAge = (d) => {
const dob = new Date(d);
const today = new Date();
let a = today.getFullYear() - dob.getFullYear();
const m = today.getMonth() - dob.getMonth();
if (m < 0 || (m === 0 && today.getDate() < dob.getDate())) a--;
return a;
};
/* attach to every modal edit-form */
document.querySelectorAll('.student-edit-form').forEach(form => {
const feedback = (el, msg) => {
let f = el.nextElementSibling;
if (!f || !f.classList.contains('invalid-feedback')) {
f = document.createElement('div');
f.className = 'invalid-feedback';
el.after(f);
}
f.textContent = msg;
el.classList.add('is-invalid');
};
const clear = el => {
el.classList.remove('is-invalid');
const f = el.nextElementSibling;
if (f && f.classList.contains('invalid-feedback')) f.textContent = '';
};
/* live input validation */
form.addEventListener('input', e => {
const t = e.target;
clear(t); // reset first
if (t.name === 'firstname' || t.name === 'lastname') {
if (!nameRE.test(t.value.trim())) {
feedback(t, 'Only letters, spaces or dashes (2-30)');
}
}
if (t.name === 'registration_grade') {
if (!gradeRE.test(t.value.trim())) {
feedback(t, 'Invalid grade value');
}
}
if (t.name === 'dob') {
const age = calcAge(t.value);
if (!t.value || age < MIN_AGE || age > MAX_AGE) {
feedback(t, `Age must be ${MIN_AGE}-${MAX_AGE}`);
}
}
});
/* submit validation */
form.addEventListener('submit', e => {
let firstBad = null;
form.querySelectorAll('input,select').forEach(el => clear(el)); // reset all
const fname = form.querySelector('[name="firstname"]');
const lname = form.querySelector('[name="lastname"]');
const dob = form.querySelector('[name="dob"]');
const grade = form.querySelector('[name="registration_grade"]');
const gender= form.querySelector('[name="gender"]');
const photo = form.querySelector('[name="photo_consent"]');
/* run checks */
if (!nameRE.test(fname.value.trim())) {
feedback(fname,'Only letters, spaces or dashes (2-30)'); firstBad ??= fname;
}
if (!nameRE.test(lname.value.trim())) {
feedback(lname,'Only letters, spaces or dashes (2-30)'); firstBad ??= lname;
}
const age = calcAge(dob.value);
if (!dob.value || age < MIN_AGE || age > MAX_AGE) {
feedback(dob,`Age must be ${MIN_AGE}-${MAX_AGE}`); firstBad ??= dob;
}
if (!gender.value) {
feedback(gender,'Required'); firstBad ??= gender;
}
if (!photo.value) {
feedback(photo,'Required'); firstBad ??= photo;
}
if (!gradeRE.test(grade.value.trim())) {
feedback(grade,'Invalid grade'); firstBad ??= grade;
}
if (firstBad) {
e.preventDefault();
firstBad.focus();
}
});
});
console.log('modal_validation.js initialised ✅');
});