fix close year and ignore not active students
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 48s
Tests / PHPUnit (push) Successful in 1m17s

This commit is contained in:
root
2026-08-20 17:27:28 -04:00
parent 2b0206e7f2
commit 127098b87c
4 changed files with 346 additions and 98 deletions
+246 -48
View File
@@ -345,7 +345,70 @@ foreach (($students ?? []) as $student) {
<div data-step-panel="0">
<h6 class="fw-semibold">Review student information</h6>
<div class="text-muted small mb-3">Select each student you want to enroll for <?= esc($selectedYear ?? 'the selected school year') ?> and update their information if needed.</div>
<div class="text-muted small mb-3">Select each student you want to enroll for <?= esc($selectedYear ?? 'the selected school year') ?>. Photo consent, medical conditions, and allergies can be updated below.</div>
<?php
$enrollmentMedicalOptions = [
'None',
'ADHD (Attention-Deficit/Hyperactivity Disorder)',
'Anxiety or Emotional Disorders',
'Asthma',
'Autism Spectrum Disorder (ASD)',
'Behavioral or Conduct Disorders',
'Blindness / Vision Impairment',
'Celiac Disease (Gluten Intolerance)',
'Cerebral Palsy',
'Cystic Fibrosis',
'Depression',
'Diabetes (Type 1 or Type 2)',
'Down Syndrome',
'Dyslexia or Learning Disabilities',
'Eating Disorders',
'Eczema / Severe Skin Conditions',
'Epilepsy / Seizure Disorders',
'Hearing Impairments / Deafness',
'Heart Conditions (congenital or acquired)',
'Hemophilia / Bleeding Disorders',
'Kidney Disease',
'Migraines / Chronic Headaches',
'Obsessive-Compulsive Disorder (OCD)',
'Physical Disabilities / Mobility Impairments',
'PTSD (Post-Traumatic Stress Disorder)',
'Sickle Cell Anemia',
'Speech and Language Disorders',
'Thyroid Disorders',
'Tourette Syndrome',
'Traumatic Brain Injury (TBI)',
'Rheumatic diseases',
'Ulcerative Colitis / Crohns Disease',
'Other',
];
$enrollmentAllergyOptions = [
'None',
'Animal Dander (cats, dogs, etc.)',
'Antibiotics',
'Bee stings',
'Cockroach',
'Corn',
'Dust Mites',
'Egg',
'Fire ant stings',
'Fish',
'Fragrances / Perfumes',
'Latex',
'Milk / Dairy',
'Mold',
'Mosquito bites',
'Peanut',
'Pollen (grass, tree, weed)',
'Sesame',
'Shellfish (shrimp, crab, lobster, etc.)',
'Soy',
'Tree Nuts (almond, cashew, walnut, etc.)',
'Wasp stings',
'Wheat / Gluten',
'Other',
];
?>
<div class="d-grid gap-2">
<?php foreach ($students as $student): ?>
<?php
@@ -360,6 +423,25 @@ foreach (($students ?? []) as $student) {
$gradeLabel = $section
? preg_replace_callback('/\byouth\b/i', fn($m) => ucfirst(strtolower($m[0])), (string) $section)
: 'Not Assigned';
$medicalSelected = is_array($student['medical_conditions'] ?? null)
? array_values(array_filter(array_map('trim', $student['medical_conditions'])))
: array_values(array_filter(array_map('trim', preg_split('/[,\n;]+/', (string) ($student['medical_conditions'] ?? ''), -1, PREG_SPLIT_NO_EMPTY) ?: [])));
$allergySelected = is_array($student['allergies'] ?? null)
? array_values(array_filter(array_map('trim', $student['allergies'])))
: array_values(array_filter(array_map('trim', preg_split('/[,\n;]+/', (string) ($student['allergies'] ?? ''), -1, PREG_SPLIT_NO_EMPTY) ?: [])));
$medicalOther = implode(', ', array_diff($medicalSelected, $enrollmentMedicalOptions));
$allergyOther = implode(', ', array_diff($allergySelected, $enrollmentAllergyOptions));
if ($medicalOther !== '') {
$medicalSelected[] = 'Other';
}
if ($allergyOther !== '') {
$allergySelected[] = 'Other';
}
$dobDisplay = !empty($student['dob']) ? local_date($student['dob'], 'm-d-Y') : 'N/A';
$photoConsentValue = (string) ($student['photo_consent'] ?? '');
if ($photoConsentValue !== '0' && $photoConsentValue !== '1') {
$photoConsentValue = !empty($student['photo_consent']) ? '1' : '';
}
?>
<div class="student-select-card <?= $canEnroll ? '' : 'is-disabled' ?>"
data-student-card
@@ -376,56 +458,65 @@ foreach (($students ?? []) as $student) {
<div class="fw-semibold"><?= esc($studentName) ?></div>
<?= $statusBadge($student['enrollment_status'] ?? '') ?>
</div>
<div class="small text-muted">Current grade: <?= esc($gradeLabel) ?> &middot; School ID: <?= esc($student['school_id'] ?? 'N/A') ?></div>
<div class="small text-muted mt-1">
<div>School ID: <?= esc($student['school_id'] ?? 'N/A') ?></div>
<div>Date of birth: <?= esc($dobDisplay) ?><?php if (isset($student['age'])): ?> &middot; Age: <?= esc($student['age']) ?><?php endif; ?></div>
<div>Gender: <?= esc($student['gender'] ?? 'N/A') ?></div>
<div>Registration grade: <?= esc($student['registration_grade'] ?? 'N/A') ?></div>
<div>Current grade: <?= esc($gradeLabel) ?></div>
<div>Expected placement: <?= esc($student['expected_placement_label'] ?? $gradeLabel) ?></div>
<div>Required action: <?= esc($student['required_action_label'] ?? 'Contact administration') ?></div>
</div>
<?php if ($canEnroll): ?>
<div class="row g-2 mt-2" data-student-edit-fields>
<div class="col-md-6">
<label class="form-label small fw-semibold" for="student-firstname-<?= esc($student['id']) ?>">First name</label>
<input class="form-control form-control-sm" type="text" id="student-firstname-<?= esc($student['id']) ?>" name="student_info[<?= esc($student['id']) ?>][firstname]" value="<?= esc($student['firstname'] ?? '') ?>" required maxlength="30" disabled data-student-edit-input>
</div>
<div class="col-md-6">
<label class="form-label small fw-semibold" for="student-lastname-<?= esc($student['id']) ?>">Last name</label>
<input class="form-control form-control-sm" type="text" id="student-lastname-<?= esc($student['id']) ?>" name="student_info[<?= esc($student['id']) ?>][lastname]" value="<?= esc($student['lastname'] ?? '') ?>" required maxlength="30" disabled data-student-edit-input>
<input type="hidden" name="student_info[<?= esc($student['id']) ?>][firstname]" value="<?= esc($student['firstname'] ?? '') ?>">
<input type="hidden" name="student_info[<?= esc($student['id']) ?>][lastname]" value="<?= esc($student['lastname'] ?? '') ?>">
<input type="hidden" name="student_info[<?= esc($student['id']) ?>][dob]" value="<?= esc($student['dob'] ?? '') ?>">
<input type="hidden" name="student_info[<?= esc($student['id']) ?>][gender]" value="<?= esc($student['gender'] ?? '') ?>">
<input type="hidden" name="student_info[<?= esc($student['id']) ?>][registration_grade]" value="<?= esc($student['registration_grade'] ?? '') ?>">
<div class="row g-2 mt-3" data-student-edit-fields>
<div class="col-12">
<div class="fw-semibold small mb-1">Editable health information</div>
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold" for="student-dob-<?= esc($student['id']) ?>">Date of birth</label>
<input class="form-control form-control-sm" type="date" id="student-dob-<?= esc($student['id']) ?>" name="student_info[<?= esc($student['id']) ?>][dob]" value="<?= esc($student['dob'] ?? '') ?>" required disabled data-student-edit-input>
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold" for="student-gender-<?= esc($student['id']) ?>">Gender</label>
<select class="form-select form-select-sm" id="student-gender-<?= esc($student['id']) ?>" name="student_info[<?= esc($student['id']) ?>][gender]" required disabled data-student-edit-input>
<option value="">Select</option>
<option value="Male" <?= ($student['gender'] ?? '') === 'Male' ? 'selected' : '' ?>>Male</option>
<option value="Female" <?= ($student['gender'] ?? '') === 'Female' ? 'selected' : '' ?>>Female</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold" for="student-grade-<?= esc($student['id']) ?>">Registration grade</label>
<input class="form-control form-control-sm" type="text" id="student-grade-<?= esc($student['id']) ?>" name="student_info[<?= esc($student['id']) ?>][registration_grade]" value="<?= esc($student['registration_grade'] ?? '') ?>" required maxlength="50" disabled data-student-edit-input>
</div>
<div class="col-md-6">
<label class="form-label small fw-semibold" for="student-photo-consent-<?= esc($student['id']) ?>">Photo consent</label>
<select class="form-select form-select-sm" id="student-photo-consent-<?= esc($student['id']) ?>" name="student_info[<?= esc($student['id']) ?>][photo_consent]" required disabled data-student-edit-input>
<option value="">Select</option>
<option value="1" <?= (string) ($student['photo_consent'] ?? '') === '1' ? 'selected' : '' ?>>Yes</option>
<option value="0" <?= (string) ($student['photo_consent'] ?? '') === '0' ? 'selected' : '' ?>>No</option>
<option value="1" <?= $photoConsentValue === '1' ? 'selected' : '' ?>>Yes</option>
<option value="0" <?= $photoConsentValue === '0' ? 'selected' : '' ?>>No</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label small fw-semibold">Expected placement</label>
<div class="form-control form-control-sm bg-light"><?= esc($student['expected_placement_label'] ?? $gradeLabel) ?></div>
<div class="col-md-4">
<label class="form-label small fw-semibold">Medical conditions</label>
<div class="border rounded p-2 bg-white small" style="max-height: 180px; overflow-y: auto;" data-health-group="medical_conditions">
<?php foreach ($enrollmentMedicalOptions as $opt): ?>
<?php $optId = 'student-medical-' . $student['id'] . '-' . md5($opt); ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="<?= esc($optId) ?>" name="student_info[<?= esc($student['id']) ?>][medical_conditions][]" value="<?= esc($opt) ?>" <?= in_array($opt, $medicalSelected, true) ? 'checked' : '' ?> disabled data-student-edit-input data-health-option="<?= $opt === 'Other' ? 'other' : ($opt === 'None' ? 'none' : 'item') ?>">
<label class="form-check-label" for="<?= esc($optId) ?>"><?= esc($opt) ?></label>
</div>
<?php endforeach; ?>
</div>
<input type="text" class="form-control form-control-sm mt-2 <?= $medicalOther === '' ? 'd-none' : '' ?>" name="student_info[<?= esc($student['id']) ?>][medical_condition_other]" value="<?= esc($medicalOther) ?>" placeholder="Please specify if Other is selected" disabled data-student-edit-input data-other-input="medical_conditions" maxlength="100">
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold">Allergies</label>
<div class="border rounded p-2 bg-white small" style="max-height: 180px; overflow-y: auto;" data-health-group="allergies">
<?php foreach ($enrollmentAllergyOptions as $opt): ?>
<?php $optId = 'student-allergy-' . $student['id'] . '-' . md5($opt); ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="<?= esc($optId) ?>" name="student_info[<?= esc($student['id']) ?>][allergies][]" value="<?= esc($opt) ?>" <?= in_array($opt, $allergySelected, true) ? 'checked' : '' ?> disabled data-student-edit-input data-health-option="<?= $opt === 'Other' ? 'other' : ($opt === 'None' ? 'none' : 'item') ?>">
<label class="form-check-label" for="<?= esc($optId) ?>"><?= esc($opt) ?></label>
</div>
<?php endforeach; ?>
</div>
<input type="text" class="form-control form-control-sm mt-2 <?= $allergyOther === '' ? 'd-none' : '' ?>" name="student_info[<?= esc($student['id']) ?>][allergy_other]" value="<?= esc($allergyOther) ?>" placeholder="Please specify if Other is selected" disabled data-student-edit-input data-other-input="allergies" maxlength="100">
</div>
</div>
<?php else: ?>
<div class="small text-muted">
Date of birth: <?= esc(!empty($student['dob']) ? local_date($student['dob'], 'm-d-Y') : 'N/A') ?>
<?php if (isset($student['age'])): ?>
&middot; Age: <?= esc($student['age']) ?>
<?php endif; ?>
</div>
<div class="small text-muted">Expected placement: <?= esc($student['expected_placement_label'] ?? $gradeLabel) ?></div>
<?php endif; ?>
<div class="small">Required action: <?= esc($student['required_action_label'] ?? 'Contact administration') ?></div>
<?php if (($eligibilityMessage['message'] ?? '') !== ''): ?>
<div class="alert alert-<?= esc($eligibilityMessage['level'] ?? 'info') ?> py-2 px-3 mt-2 mb-0 small">
<?= esc($eligibilityMessage['message']) ?>
@@ -462,9 +553,6 @@ foreach (($students ?? []) as $student) {
<div class="col-md-4"><span class="text-muted">Previous-year carry-over balance:</span> <strong data-financial-value="carry_over_balance"><?= esc($money($familyFinancialSummary['carry_over_balance'] ?? 0)) ?></strong></div>
<div class="col-md-4"><span class="text-muted">Total currently due:</span> <strong data-financial-value="amount_due"><?= esc($money($familyFinancialSummary['amount_due'] ?? 0)) ?></strong></div>
</div>
<?php if (!empty($familyFinancialSummary['policy_message'])): ?>
<div class="small text-muted mt-2"><?= esc($familyFinancialSummary['policy_message']) ?></div>
<?php endif; ?>
</div>
<?php else: ?>
<div class="alert alert-warning mb-0">Family account information is not available. Please contact the administration if you have questions about tuition or balance.</div>
@@ -476,7 +564,7 @@ foreach (($students ?? []) as $student) {
<div class="text-muted small mb-3">Review the enrollment summary before submitting.</div>
<div class="mb-3">
<div class="fw-semibold mb-2">Fees by student</div>
<div class="fw-semibold mb-2">Summary</div>
<div id="enrollmentFeeReviewList" class="d-grid gap-2"></div>
</div>
@@ -509,11 +597,8 @@ foreach (($students ?? []) as $student) {
<div class="alert alert-warning mb-0 small">
<div class="fw-semibold mb-1">Important information</div>
<ul class="mb-0 ps-3">
<li>Submitting sends the selected enrollment(s) to admission review.</li>
<li>For newly registered students, enrollment status changes to admission under review after submitting the request.</li>
<li>Payments are processed on the first day of school.</li>
<?php if (!empty($familyFinancialSummary['policy_message'])): ?>
<li><?= esc($familyFinancialSummary['policy_message']) ?></li>
<?php endif; ?>
<?php if (!empty($fallMakeupExamOn)): ?>
<li>Students with a make-up exam decision may initially remain in the same grade until the make-up exam result is confirmed.</li>
<?php endif; ?>
@@ -721,8 +806,118 @@ foreach (($students ?? []) as $student) {
card.querySelectorAll('[data-student-edit-input]').forEach(field => {
field.disabled = !enabled;
});
syncHealthGroup(card, 'medical_conditions');
syncHealthGroup(card, 'allergies');
}
function syncHealthGroup(card, groupName) {
const selected = !!card.querySelector('[data-enroll-input]')?.checked;
const group = card.querySelector('[data-health-group="' + groupName + '"]');
const otherInput = card.querySelector('[data-other-input="' + groupName + '"]');
if (!group) {
return;
}
const noneChecked = !!group.querySelector('[data-health-option="none"]:checked');
const otherChecked = !!group.querySelector('[data-health-option="other"]:checked');
group.querySelectorAll('input[type="checkbox"]').forEach(input => {
if (!selected) {
input.disabled = true;
return;
}
if (input.dataset.healthOption === 'none') {
input.disabled = false;
return;
}
if (noneChecked) {
input.checked = false;
input.disabled = true;
return;
}
input.disabled = false;
});
if (otherInput) {
otherInput.classList.toggle('d-none', !otherChecked);
otherInput.disabled = !selected || !otherChecked;
if (!otherChecked) {
otherInput.value = '';
}
}
}
function validateSelectedStudentHealth() {
for (const input of selectedEnrollInputs()) {
const card = input.closest('[data-student-card]');
if (!card) {
continue;
}
const name = card.querySelector('.fw-semibold')?.textContent?.trim() || 'Student';
const photo = card.querySelector("select[name$='[photo_consent]']");
if (!photo || photo.value === '') {
alert('Please select photo consent for ' + name + '.');
return false;
}
const medicalChecked = card.querySelectorAll('[data-health-group="medical_conditions"] input[type="checkbox"]:checked');
if (!medicalChecked.length) {
alert('Please select medical conditions for ' + name + '.');
return false;
}
const medicalOther = card.querySelector('[data-other-input="medical_conditions"]');
if (card.querySelector('[data-health-group="medical_conditions"] [data-health-option="other"]:checked') && (!medicalOther || !medicalOther.value.trim())) {
alert('Please specify the other medical condition for ' + name + '.');
return false;
}
const allergyChecked = card.querySelectorAll('[data-health-group="allergies"] input[type="checkbox"]:checked');
if (!allergyChecked.length) {
alert('Please select allergies for ' + name + '.');
return false;
}
const allergyOther = card.querySelector('[data-other-input="allergies"]');
if (card.querySelector('[data-health-group="allergies"] [data-health-option="other"]:checked') && (!allergyOther || !allergyOther.value.trim())) {
alert('Please specify the other allergy for ' + name + '.');
return false;
}
}
return true;
}
document.querySelectorAll('[data-student-card]').forEach(card => {
card.querySelectorAll('[data-health-group]').forEach(group => {
group.addEventListener('change', function(event) {
const target = event.target;
if (!(target instanceof HTMLInputElement) || target.type !== 'checkbox') {
return;
}
const groupName = group.getAttribute('data-health-group');
if (!groupName) {
return;
}
if (target.dataset.healthOption === 'none' && target.checked) {
group.querySelectorAll('[data-health-option="item"], [data-health-option="other"]').forEach(input => {
input.checked = false;
});
}
if ((target.dataset.healthOption === 'item' || target.dataset.healthOption === 'other') && target.checked) {
const noneInput = group.querySelector('[data-health-option="none"]');
if (noneInput) {
noneInput.checked = false;
}
}
syncHealthGroup(card, groupName);
});
});
});
if (startButton && flowModal) {
startButton.addEventListener('click', function() {
if (deadlinePassed) {
@@ -768,6 +963,9 @@ foreach (($students ?? []) as $student) {
alert('Please select at least one student to enroll.');
return;
}
if (currentStep === 0 && !validateSelectedStudentHealth()) {
return;
}
if (currentStep === 1) {
syncPolicyAccepted();
if (!hasAcceptedSchoolPolicy) {