Files
alrahma_sunday_school/app/Views/parent/enroll_classes.php
T
root 889c037660
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 48s
Tests / PHPUnit (push) Failing after 1m22s
fix is_new issue with enrollment fixes
2026-08-20 19:57:25 -04:00

1341 lines
73 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?= $this->extend('layout/main_layout') ?>
<?= $this->section('styles') ?>
<style>
.enrollment-start-panel {
border: 1px solid #d8e7dc;
border-radius: 8px;
background: #f8fbf8;
padding: 1rem;
}
.enrollment-stepper {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: .5rem;
}
.enrollment-step {
border-bottom: 3px solid #dee2e6;
color: #6c757d;
font-size: .85rem;
line-height: 1.2;
overflow-wrap: anywhere;
padding: .35rem 0;
text-align: center;
}
.enrollment-step.is-active {
border-color: #198754;
color: #198754;
font-weight: 700;
}
.student-select-card {
border: 1px solid #dee2e6;
border-radius: 8px;
cursor: pointer;
padding: .85rem;
transition: border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}
.student-select-card.is-selected {
background: #eef8f0;
border-color: #198754;
box-shadow: 0 0 0 .15rem rgba(25, 135, 84, .14);
}
.student-select-card.is-disabled {
background: #f8f9fa;
color: #6c757d;
cursor: not-allowed;
}
.student-select-icon {
align-items: center;
border: 1px solid #adb5bd;
border-radius: 50%;
display: inline-flex;
height: 1.65rem;
justify-content: center;
width: 1.65rem;
}
.student-select-card.is-selected .student-select-icon {
background: #198754;
border-color: #198754;
color: #fff;
}
.enrollment-policy-frame {
border: 1px solid #dee2e6;
border-radius: 8px;
height: min(54vh, 520px);
min-height: 320px;
width: 100%;
}
.enrollment-withdraw-control {
align-items: center;
display: inline-flex;
gap: .5rem;
justify-content: flex-end;
min-width: max-content;
padding-left: 0;
white-space: nowrap;
}
.enrollment-withdraw-control .form-check-input {
flex: 0 0 auto;
margin-left: 0;
}
.enrollment-modal-footer {
gap: .5rem;
}
.enrollment-summary-card {
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 1rem;
}
.enrollment-summary-lines {
display: grid;
gap: .35rem;
}
.enrollment-summary-line {
align-items: baseline;
display: flex;
gap: .5rem;
justify-content: space-between;
}
.enrollment-summary-label {
color: #6c757d;
flex: 0 0 auto;
font-size: .875rem;
}
.enrollment-summary-value {
font-size: .875rem;
font-weight: 600;
min-width: 0;
overflow-wrap: anywhere;
text-align: right;
}
@media (max-width: 575.98px) {
.enrollment-stepper {
gap: .25rem;
}
.enrollment-step {
font-size: .72rem;
}
.enrollment-modal-footer {
align-items: stretch;
flex-direction: column;
}
.enrollment-modal-footer .btn {
width: 100%;
}
.student-select-card {
padding: .75rem;
}
.enrollment-status-table,
.enrollment-status-table thead,
.enrollment-status-table tbody,
.enrollment-status-table tr,
.enrollment-status-table th,
.enrollment-status-table td {
display: block;
width: 100%;
}
.enrollment-status-table thead {
display: none;
}
.enrollment-status-table {
border: 0;
}
.enrollment-status-table tr {
border: 1px solid #dee2e6;
border-radius: 8px;
margin-bottom: .85rem;
overflow: hidden;
}
.enrollment-status-table td {
align-items: flex-start;
border-bottom: 1px solid #eef1f3;
display: flex;
gap: .75rem;
justify-content: space-between;
padding: .75rem;
text-align: right;
}
.enrollment-status-table td:last-child {
border-bottom: 0;
}
.enrollment-status-table td::before {
color: #6c757d;
content: attr(data-label);
flex: 0 0 42%;
font-size: .8rem;
font-weight: 700;
text-align: left;
}
.enrollment-status-table td > * {
max-width: 58%;
}
.enrollment-status-table td[data-label="Withdraw"] {
align-items: center;
}
.enrollment-status-table td[data-label="Withdraw"] > * {
max-width: none;
}
.enrollment-status-table td[data-label="Withdraw"] .enrollment-withdraw-control {
margin-left: auto;
}
.enrollment-summary-line {
align-items: flex-start;
display: block;
}
.enrollment-summary-value {
display: block;
text-align: left;
}
}
</style>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?php
$tz = (string) (config('School')->attendance['timezone'] ?? user_timezone());
$deadlineObj = (new DateTime($lastDayOfRegistration, new DateTimeZone($tz)))->setTime(23, 59, 59);
$nowObj = new DateTime('now', new DateTimeZone($tz));
$deadlinePassed = $nowObj > $deadlineObj;
$hasAcceptedSchoolPolicy = (bool) ($hasAcceptedSchoolPolicy ?? false);
$familyFinancialSummary = is_array($familyFinancialSummary ?? null) ? $familyFinancialSummary : [];
$enrollmentFeeSchedule = is_array($enrollmentFeeSchedule ?? null) ? $enrollmentFeeSchedule : [];
$money = static function ($amount) use ($familyFinancialSummary): string {
$currency = (string) ($familyFinancialSummary['currency'] ?? '$');
return $currency . number_format((float) $amount, 2);
};
$statusBadge = static function (?string $status): string {
$status = strtolower(trim((string) $status));
return match ($status) {
'admission under review' => '<span class="badge bg-primary">admission under review</span>',
'review & decision' => '<span class="badge bg-secondary">review &amp; decision</span>',
'payment pending' => '<span class="badge bg-warning text-dark">payment pending</span>',
'enrolled' => '<span class="badge bg-success">enrolled</span>',
'withdraw under review' => '<span class="badge bg-warning text-dark">withdraw under review</span>',
'refund pending' => '<span class="badge bg-info text-dark">refund pending</span>',
'withdrawn' => '<span class="badge bg-danger">withdrawn</span>',
'waitlist' => '<span class="badge bg-secondary">waitlist</span>',
'denied' => '<span class="badge bg-danger">denied</span>',
'not enrolled' => '<span class="badge bg-light text-dark">not enrolled</span>',
default => '<span class="badge bg-light text-dark">unknown</span>',
};
};
$enrollableCount = 0;
$withdrawableCount = 0;
foreach (($students ?? []) as $student) {
$eligibilityMessage = is_array($student['enrollment_eligibility_message'] ?? null) ? $student['enrollment_eligibility_message'] : ['blocking' => false];
if (($student['enrollment_status'] ?? '') === 'not enrolled' && !$deadlinePassed && $isEditable && empty($eligibilityMessage['blocking'])) {
$enrollableCount++;
}
if (($student['enrollment_status'] ?? '') === 'enrolled' && $isEditable) {
$withdrawableCount++;
}
}
?>
<div class="container my-4">
<div class="text-center mb-4">
<h3 class="text-success" style="font-family: Arial, sans-serif;">Enroll in Classes</h3>
<?php if (!empty($selectedYear)): ?>
<div class="text-muted small">School Year: <?= esc($selectedYear) ?></div>
<?php endif; ?>
</div>
<?php
$flashError = session()->getFlashdata('error');
$flashSuccess = session()->getFlashdata('success');
?>
<?php if ($flashError): ?>
<div class="alert alert-danger"><?= esc($flashError) ?></div>
<?php endif; ?>
<?php if ($flashSuccess): ?>
<div class="alert alert-success"><?= esc($flashSuccess) ?></div>
<?php endif; ?>
<div class="alert alert-info mb-3">
<p>Enrollment is the process of officially signing up your child for the upcoming school year.</p>
<ul class="mb-0">
<li>Last Day for Enrollment is <strong><?= esc(local_date($lastDayOfRegistration, 'm-d-Y')) ?></strong>.</li>
<li>Payments are processed on the first day of school: <strong><?= esc(local_date($schoolStartDate, 'm-d-Y')) ?></strong>.</li>
</ul>
</div>
<?php if (!empty($students)): ?>
<form action="<?= base_url('/parent/enroll_classes_handler') ?>" method="post" id="enrollmentFlowForm">
<?= csrf_field() ?>
<input type="hidden" id="accept_school_policy_input" name="accept_school_policy" value="<?= $hasAcceptedSchoolPolicy ? '1' : '0' ?>">
<div class="enrollment-start-panel mb-4">
<div class="row g-3 align-items-center">
<div class="col-lg">
<div class="fw-semibold">Enrollment process</div>
<div class="text-muted small">
Review student information, confirm your home address and phone, acknowledge policies, review tuition and balances, then submit enrollment.
</div>
</div>
<div class="col-lg-auto">
<button type="button"
class="btn btn-success btn-lg w-100"
id="startEnrollmentButton"
<?= (!$isEditable || $enrollableCount === 0 || $deadlinePassed) ? 'disabled' : '' ?>>
Start Enrollment
</button>
</div>
</div>
<?php if ($deadlinePassed): ?>
<div class="small text-danger mt-2">Enrollment closed on <?= esc($deadlineObj->format('m-d-Y')) ?>.</div>
<?php elseif ($enrollableCount === 0): ?>
<div class="small text-muted mt-2">No students are currently available for new enrollment.</div>
<?php endif; ?>
</div>
<div class="table-responsive mb-4">
<table class="table table-striped table-bordered align-middle enrollment-status-table">
<thead>
<tr>
<th>Student</th>
<th>Grade</th>
<th>Decision</th>
<th>Required Action</th>
<th>Status</th>
<th>Withdraw</th>
</tr>
</thead>
<tbody>
<?php foreach ($students as $student): ?>
<?php
$studentName = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? ''));
$studentName = $studentName !== '' ? $studentName : 'Student';
$section = $student['class_section'] ?? null;
$gradeLabel = $section
? preg_replace_callback('/\byouth\b/i', fn($m) => ucfirst(strtolower($m[0])), (string) $section)
: 'Not Assigned';
?>
<tr>
<td data-label="Student">
<div class="fw-semibold"><?= esc($studentName) ?></div>
<div class="text-muted small">School ID: <?= esc($student['school_id'] ?? 'N/A') ?></div>
</td>
<td data-label="Grade"><?= esc($gradeLabel) ?></td>
<td data-label="Decision"><?= esc($student['transition_evaluation']['decision_label'] ?? 'Pending') ?></td>
<td data-label="Required Action"><?= esc($student['required_action_label'] ?? 'Contact administration') ?></td>
<td data-label="Status"><?= $statusBadge($student['enrollment_status'] ?? '') ?></td>
<td data-label="Withdraw">
<?php if (($student['enrollment_status'] ?? '') === 'enrolled'): ?>
<div class="form-check form-switch m-0 enrollment-withdraw-control">
<input class="form-check-input" type="checkbox" name="withdraw[]" value="<?= esc($student['id']) ?>" id="withdraw-<?= esc($student['id']) ?>" <?= !$isEditable ? 'disabled' : '' ?>>
<label class="form-check-label small" for="withdraw-<?= esc($student['id']) ?>">Request</label>
</div>
<?php elseif (($student['enrollment_status'] ?? '') === 'withdrawn'): ?>
<span class="text-muted small">Withdrawn</span>
<?php else: ?>
<span class="text-muted small">Unavailable</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php if ($withdrawableCount > 0): ?>
<div class="d-flex justify-content-center mb-4">
<button type="submit" class="btn btn-outline-danger" id="withdrawSubmitButton">Submit Withdrawal Request</button>
</div>
<?php endif; ?>
<div class="modal fade" id="enrollmentFlowModal" tabindex="-1" aria-labelledby="enrollmentFlowModalLabel" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog modal-xl modal-dialog-scrollable modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header bg-success text-white">
<h5 class="modal-title" id="enrollmentFlowModalLabel">Submit Enrollment</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="enrollment-stepper mb-3" aria-label="Enrollment steps">
<div class="enrollment-step is-active" data-step-indicator="0">Student Info</div>
<div class="enrollment-step" data-step-indicator="1">Contact</div>
<div class="enrollment-step" data-step-indicator="2">Policies</div>
<div class="enrollment-step" data-step-indicator="3">Tuition</div>
<div class="enrollment-step" data-step-indicator="4">Submit</div>
</div>
<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') ?>. 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
$eligibilityMessage = is_array($student['enrollment_eligibility_message'] ?? null) ? $student['enrollment_eligibility_message'] : ['message' => '', 'blocking' => false, 'level' => 'info'];
$studentName = trim((string) ($student['firstname'] ?? '') . ' ' . (string) ($student['lastname'] ?? ''));
$studentName = $studentName !== '' ? $studentName : 'Student';
$canEnroll = ($student['enrollment_status'] ?? '') === 'not enrolled'
&& !$deadlinePassed
&& $isEditable
&& empty($eligibilityMessage['blocking']);
$section = $student['class_section'] ?? null;
$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
data-student-id="<?= esc($student['id']) ?>"
data-school-id="<?= esc($student['school_id'] ?? 'N/A') ?>"
data-current-grade="<?= esc($gradeLabel) ?>"
data-required-action="<?= esc($student['required_action_label'] ?? 'Contact administration') ?>"
data-expected-placement="<?= esc($student['expected_placement_label'] ?? $gradeLabel) ?>"
data-is-new="<?= (string) ($student['is_new'] ?? '1') === '1' ? '1' : '0' ?>"
data-selectable="<?= $canEnroll ? '1' : '0' ?>">
<div class="d-flex gap-3 align-items-start">
<span class="student-select-icon" aria-hidden="true"><i class="bi bi-check2"></i></span>
<div class="flex-grow-1">
<div class="d-flex flex-wrap gap-2 align-items-center">
<div class="fw-semibold"><?= esc($studentName) ?></div>
<?= $statusBadge($student['enrollment_status'] ?? '') ?>
</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>
<?php if ((string) ($student['is_new'] ?? '1') === '1'): ?>
<div>Registration grade: <?= esc($student['registration_grade'] ?? 'N/A') ?></div>
<?php endif; ?>
<?php if ((string) ($student['is_new'] ?? '0') === '0'): ?>
<div>Expected placement: <?= esc($student['expected_placement_label'] ?? $gradeLabel) ?></div>
<?php endif; ?>
</div>
<?php if ($canEnroll): ?>
<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 information</div>
</div>
<div class="col-md-4">
<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" <?= $photoConsentValue === '1' ? 'selected' : '' ?>>Yes</option>
<option value="0" <?= $photoConsentValue === '0' ? 'selected' : '' ?>>No</option>
</select>
</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 endif; ?>
<?php if (($eligibilityMessage['message'] ?? '') !== ''): ?>
<div class="alert alert-<?= esc($eligibilityMessage['level'] ?? 'info') ?> py-2 px-3 mt-2 mb-0 small">
<?= esc($eligibilityMessage['message']) ?>
</div>
<?php endif; ?>
</div>
</div>
<?php if ($canEnroll): ?>
<input class="d-none" type="checkbox" name="enroll[]" value="<?= esc($student['id']) ?>" data-enroll-input>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="d-none" data-step-panel="1">
<?php
$parentContact = is_array($parentContact ?? null) ? $parentContact : [];
$parentContactStates = [
'CT' => 'Connecticut',
'ME' => 'Maine',
'MA' => 'Massachusetts',
'NH' => 'New Hampshire',
'NY' => 'New York',
'RI' => 'Rhode Island',
'VT' => 'Vermont',
];
$currentParentState = strtoupper(trim((string) ($parentContact['state'] ?? '')));
if ($currentParentState !== '' && ! isset($parentContactStates[$currentParentState])) {
$parentContactStates[$currentParentState] = $currentParentState;
}
$parentDisplayName = trim((string) ($parentContact['firstname'] ?? '') . ' ' . (string) ($parentContact['lastname'] ?? ''));
?>
<h6 class="fw-semibold">Confirm home address and phone</h6>
<div class="text-muted small mb-3">
Please review and update your contact information before continuing enrollment.
<?php if ($parentDisplayName !== ''): ?>
This account is for <?= esc($parentDisplayName) ?>.
<?php endif; ?>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label small fw-semibold" for="parent-contact-cellphone">Phone</label>
<input type="tel"
class="form-control"
id="parent-contact-cellphone"
name="parent_contact[cellphone]"
value="<?= esc($parentContact['cellphone'] ?? '') ?>"
maxlength="12"
inputmode="numeric"
required>
</div>
<div class="col-md-8">
<label class="form-label small fw-semibold" for="parent-contact-street">Home street address</label>
<input type="text"
class="form-control"
id="parent-contact-street"
name="parent_contact[address_street]"
value="<?= esc($parentContact['address_street'] ?? '') ?>"
maxlength="255"
required>
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold" for="parent-contact-apt">Apt / Unit</label>
<input type="text"
class="form-control"
id="parent-contact-apt"
name="parent_contact[apt]"
value="<?= esc($parentContact['apt'] ?? '') ?>"
maxlength="15">
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold" for="parent-contact-city">City</label>
<input type="text"
class="form-control"
id="parent-contact-city"
name="parent_contact[city]"
value="<?= esc($parentContact['city'] ?? '') ?>"
maxlength="100"
required>
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold" for="parent-contact-zip">ZIP code</label>
<input type="text"
class="form-control"
id="parent-contact-zip"
name="parent_contact[zip]"
value="<?= esc($parentContact['zip'] ?? '') ?>"
maxlength="5"
inputmode="numeric"
required>
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold" for="parent-contact-state">State</label>
<select class="form-select" id="parent-contact-state" name="parent_contact[state]" required>
<option value="">Select</option>
<?php foreach ($parentContactStates as $abbr => $stateName): ?>
<option value="<?= esc($abbr) ?>" <?= $currentParentState === $abbr ? 'selected' : '' ?>><?= esc($stateName) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<div class="d-none" data-step-panel="2">
<h6 class="fw-semibold">Acknowledge school policies</h6>
<div class="text-muted small mb-3">Review the current school policies before submitting enrollment.</div>
<iframe src="<?= base_url('policy/school_policy') ?>" class="enrollment-policy-frame" frameborder="0" title="School Policies"></iframe>
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" value="1" id="schoolPolicyAcceptedCheckbox" <?= $hasAcceptedSchoolPolicy ? 'checked disabled' : '' ?>>
<label class="form-check-label" for="schoolPolicyAcceptedCheckbox">
I have read and accept all school policies.
</label>
</div>
</div>
<div class="d-none" data-step-panel="3">
<h6 class="fw-semibold">Review tuition, fees and balance</h6>
<div class="text-muted small mb-3">Review the family account information before submitting enrollment.</div>
<?php if ($familyFinancialSummary !== []): ?>
<div class="border rounded p-3 bg-light">
<div class="row g-2">
<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>
</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>
<?php endif; ?>
</div>
<div class="d-none" data-step-panel="4">
<h6 class="fw-semibold">Submit enrollment</h6>
<div class="text-muted small mb-3">Review the enrollment summary before submitting.</div>
<div class="mb-3">
<div class="fw-semibold mb-2">Summary</div>
<div id="enrollmentFeeReviewList" class="d-grid gap-2"></div>
</div>
<div class="enrollment-summary-card mb-3" id="parentContactReviewCard">
<div class="fw-semibold mb-2">Parent contact</div>
<div class="enrollment-summary-lines">
<div class="enrollment-summary-line">
<span class="enrollment-summary-label">Phone:</span>
<span class="enrollment-summary-value" data-parent-review="cellphone"></span>
</div>
<div class="enrollment-summary-line">
<span class="enrollment-summary-label">Home address:</span>
<span class="enrollment-summary-value" data-parent-review="address"></span>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<div class="border rounded p-3 h-100">
<div class="fw-semibold mb-2">School dates</div>
<div class="small"><span class="text-muted">First school day:</span> <strong><?= esc(!empty($schoolStartDate) ? local_date($schoolStartDate, 'm-d-Y') : 'TBD') ?></strong></div>
<div class="small"><span class="text-muted">Make-up exam date:</span> <strong><?= esc(!empty($fallMakeupExamOn) ? local_date($fallMakeupExamOn, 'm-d-Y') : 'No make-up exam date currently listed') ?></strong></div>
<div class="small"><span class="text-muted">Enrollment deadline:</span> <strong><?= esc(local_date($lastDayOfRegistration, 'm-d-Y')) ?></strong></div>
</div>
</div>
<div class="col-md-6">
<div class="border rounded p-3 h-100">
<div class="fw-semibold mb-2">Financial information</div>
<?php if ($familyFinancialSummary !== []): ?>
<div class="small"><span class="text-muted">Carry-over balance:</span> <strong data-financial-value="carry_over_balance"><?= esc($money($familyFinancialSummary['carry_over_balance'] ?? 0)) ?></strong></div>
<div class="small"><span class="text-muted">Tuition due now:</span> <strong data-financial-value="tuition_due_at_registration"><?= esc($money($familyFinancialSummary['tuition_due_at_registration'] ?? 0)) ?></strong></div>
<div class="small"><span class="text-muted">Total currently due:</span> <strong data-financial-value="amount_due"><?= esc($money($familyFinancialSummary['amount_due'] ?? 0)) ?></strong></div>
<?php else: ?>
<div class="small text-muted">Financial information is not available.</div>
<?php endif; ?>
</div>
</div>
</div>
<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) for newly registered students to Admissions for review.</li>
<li>Returning students who passed last year grade are automatically granted admission.</li>
<li>Payments are processed on the first day of school.</li>
<?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; ?>
<li>Contact administration if any student information, fee, or placement detail looks incorrect.</li>
</ul>
</div>
</div>
</div>
<div class="modal-footer enrollment-modal-footer">
<button type="button" class="btn btn-outline-secondary" id="enrollmentBackButton">Back</button>
<button type="button" class="btn btn-success" id="enrollmentNextButton">Next</button>
<button type="submit" class="btn btn-success d-none" id="enrollmentSubmitButton">Submit Enrollment</button>
</div>
</div>
</div>
</div>
</form>
<?php else: ?>
<p>No students found for the selected school year. Please register your kids first.</p>
<?php endif; ?>
</div>
<div class="modal fade" id="deadlineModal" tabindex="-1" aria-labelledby="deadlineModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title" id="deadlineModalLabel">Enrollment Closed</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Enrollment for the selected school year closed on <strong><?= esc($deadlineObj->format('m-d-Y')) ?></strong>.
You can still request a withdrawal if applicable.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('scripts') ?>
<script>
document.addEventListener("DOMContentLoaded", function() {
const deadlinePassed = <?= $deadlinePassed ? 'true' : 'false' ?>;
const form = document.getElementById('enrollmentFlowForm');
const startButton = document.getElementById('startEnrollmentButton');
const flowModalEl = document.getElementById('enrollmentFlowModal');
const deadlineModalEl = document.getElementById('deadlineModal');
const flowModal = flowModalEl ? new bootstrap.Modal(flowModalEl) : null;
const deadlineModal = deadlineModalEl ? new bootstrap.Modal(deadlineModalEl) : null;
const policyAcceptedInput = document.getElementById('accept_school_policy_input');
const policyAcceptedCheckbox = document.getElementById('schoolPolicyAcceptedCheckbox');
const backButton = document.getElementById('enrollmentBackButton');
const nextButton = document.getElementById('enrollmentNextButton');
const submitButton = document.getElementById('enrollmentSubmitButton');
const feeReviewList = document.getElementById('enrollmentFeeReviewList');
const parentPhoneInput = document.getElementById('parent-contact-cellphone');
const parentStreetInput = document.getElementById('parent-contact-street');
const parentAptInput = document.getElementById('parent-contact-apt');
const parentCityInput = document.getElementById('parent-contact-city');
const parentStateInput = document.getElementById('parent-contact-state');
const parentZipInput = document.getElementById('parent-contact-zip');
const finalStep = 4;
const enrollmentStartStep = <?= (int) ($enrollmentStartStep ?? 0) ?>;
const preselectedStudentIds = <?= json_encode(array_values(array_map('intval', $preselectedStudentIds ?? [])), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
const feeSchedule = <?= json_encode([
'currency' => (string) ($enrollmentFeeSchedule['currency'] ?? '$'),
'firstStudentFee' => (float) ($enrollmentFeeSchedule['first_student_fee'] ?? 0),
'secondStudentFee' => (float) ($enrollmentFeeSchedule['second_student_fee'] ?? 0),
'registrationFee' => (float) ($enrollmentFeeSchedule['registration_fee'] ?? 0),
'tuitionDueAtRegistration' => (float) ($enrollmentFeeSchedule['tuition_due_at_registration'] ?? 0),
'mandatoryFees' => (float) ($enrollmentFeeSchedule['mandatory_fees'] ?? 0),
], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
const familyFinancial = <?= json_encode([
'carryOverBalance' => (float) ($familyFinancialSummary['carry_over_balance'] ?? 0),
'registrationFee' => (float) ($familyFinancialSummary['registration_fee'] ?? 0),
'tuitionDueAtRegistration' => (float) ($familyFinancialSummary['tuition_due_at_registration'] ?? 0),
'mandatoryFees' => (float) ($familyFinancialSummary['mandatory_fees'] ?? 0),
'currentBalance' => (float) ($familyFinancialSummary['current_balance'] ?? 0),
'amountDue' => (float) ($familyFinancialSummary['amount_due'] ?? 0),
], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
let currentStep = 0;
let hasAcceptedSchoolPolicy = <?= $hasAcceptedSchoolPolicy ? 'true' : 'false' ?>;
const selectedEnrollInputs = () => form ? Array.from(form.querySelectorAll("input[name='enroll[]']:checked")) : [];
const selectedWithdrawInputs = () => form ? Array.from(form.querySelectorAll("input[name='withdraw[]']:checked")) : [];
function setStep(step) {
currentStep = Math.max(0, Math.min(finalStep, step));
document.querySelectorAll('[data-step-panel]').forEach(panel => {
panel.classList.toggle('d-none', Number(panel.dataset.stepPanel) !== currentStep);
});
document.querySelectorAll('[data-step-indicator]').forEach(indicator => {
indicator.classList.toggle('is-active', Number(indicator.dataset.stepIndicator) === currentStep);
});
backButton.classList.toggle('d-none', currentStep === 0);
nextButton.classList.toggle('d-none', currentStep === finalStep);
submitButton.classList.toggle('d-none', currentStep !== finalStep);
if (currentStep >= 3) {
updateFinancialReview();
}
if (currentStep === finalStep) {
renderReview();
}
}
function calculateSelectedTuition() {
return selectedEnrollInputs().reduce((total, input, index) => {
return total + (index === 0 ? Number(feeSchedule.firstStudentFee || 0) : Number(feeSchedule.secondStudentFee || 0));
}, 0);
}
function updateFinancialReview() {
const selectedCount = selectedEnrollInputs().length;
const tuitionDue = selectedCount > 0 ? calculateSelectedTuition() : 0;
const carryOver = Number(familyFinancial.carryOverBalance || 0);
const registrationFee = Number(familyFinancial.registrationFee || feeSchedule.registrationFee || 0);
const mandatoryFees = Number(familyFinancial.mandatoryFees || feeSchedule.mandatoryFees || 0);
const currentBalance = Number(familyFinancial.currentBalance || 0);
const amountDue = Math.max(0, carryOver) + Math.max(0, currentBalance) + registrationFee + tuitionDue + mandatoryFees;
const values = {
carry_over_balance: carryOver,
registration_fee: registrationFee,
tuition_due_at_registration: tuitionDue,
mandatory_fees: mandatoryFees,
current_balance: currentBalance,
amount_due: amountDue,
};
Object.keys(values).forEach(key => {
document.querySelectorAll('[data-financial-value="' + key + '"]').forEach(node => {
node.textContent = formatMoney(values[key]);
});
});
}
function renderReview() {
updateFinancialReview();
const cards = selectedEnrollInputs().map(input => {
const card = input.closest('[data-student-card]');
const firstName = card ? card.querySelector("input[name$='[firstname]']")?.value?.trim() : '';
const lastName = card ? card.querySelector("input[name$='[lastname]']")?.value?.trim() : '';
const dob = card ? card.querySelector("input[name$='[dob]']")?.value?.trim() : '';
const grade = card ? card.querySelector("input[name$='[registration_grade]']")?.value?.trim() : '';
const gender = card ? card.querySelector("input[name$='[gender]']")?.value?.trim() : '';
const schoolId = card?.dataset.schoolId || 'N/A';
const currentGrade = card?.dataset.currentGrade || '';
const expectedPlacement = card?.dataset.expectedPlacement || '';
const requiredAction = card?.dataset.requiredAction || '';
const isNewStudent = card?.dataset.isNew === '1';
const name = (firstName + ' ' + lastName).trim() || card?.querySelector('.fw-semibold')?.textContent?.trim() || 'Student';
return {
name,
schoolId,
dob,
gender,
registrationGrade: isNewStudent ? grade : '',
currentGrade,
expectedPlacement,
requiredAction,
};
});
if (!feeReviewList) {
return;
}
if (!cards.length) {
feeReviewList.innerHTML = '<div class="alert alert-warning mb-0">No students selected.</div>';
renderParentContactReview();
return;
}
feeReviewList.innerHTML = cards.map((student, index) => {
const tuitionFee = index === 0 ? feeSchedule.firstStudentFee : feeSchedule.secondStudentFee;
const tier = index === 0 ? 'First student tuition tier' : 'Additional student tuition tier';
const lines = [
['Student', student.name],
['School ID', student.schoolId || 'N/A'],
['Date of birth', student.dob || 'N/A'],
['Gender', student.gender || 'N/A'],
['Tuition', formatMoney(tuitionFee)],
['Current grade', student.currentGrade || 'N/A'],
['Expected placement', student.expectedPlacement || 'Pending'],
];
return '<div class="enrollment-summary-card">' +
'<div class="enrollment-summary-lines">' +
lines.map(([label, value]) => {
return '<div class="enrollment-summary-line">' +
'<span class="enrollment-summary-label">' + escapeHtml(label) + ':</span>' +
'<span class="enrollment-summary-value">' + escapeHtml(value) + '</span>' +
'</div>';
}).join('') +
'</div>' +
'</div>';
}).join('');
renderParentContactReview();
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, function(char) {
return ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' })[char];
});
}
function formatMoney(amount) {
const numericAmount = Number(amount || 0);
return String(feeSchedule.currency || '$') + numericAmount.toFixed(2);
}
function digitsOnly(value) {
return String(value || '').replace(/\D/g, '');
}
function formatPhoneDisplay(value) {
const digits = digitsOnly(value).substring(0, 10);
if (digits.length > 6) {
return digits.substring(0, 3) + '-' + digits.substring(3, 6) + '-' + digits.substring(6);
}
if (digits.length > 3) {
return digits.substring(0, 3) + '-' + digits.substring(3);
}
return digits;
}
function parentContactAddress() {
const street = parentStreetInput?.value?.trim() || '';
const apt = parentAptInput?.value?.trim() || '';
const city = parentCityInput?.value?.trim() || '';
const state = parentStateInput?.value?.trim() || '';
const zip = parentZipInput?.value?.trim() || '';
const line = [street, apt].filter(Boolean).join(', ');
const cityLine = [city, state, zip].filter(Boolean).join(' ');
return [line, cityLine].filter(Boolean).join(', ') || 'N/A';
}
function renderParentContactReview() {
const phoneNode = document.querySelector('[data-parent-review="cellphone"]');
const addressNode = document.querySelector('[data-parent-review="address"]');
if (phoneNode) {
phoneNode.textContent = formatPhoneDisplay(parentPhoneInput?.value || '') || 'N/A';
}
if (addressNode) {
addressNode.textContent = parentContactAddress();
}
}
function validateParentContact() {
const phone = digitsOnly(parentPhoneInput?.value || '');
if (phone.length !== 10) {
alert('Please enter a valid 10-digit phone number.');
parentPhoneInput?.focus();
return false;
}
if (!parentStreetInput || parentStreetInput.value.trim().length < 5) {
alert('Please enter your home street address.');
parentStreetInput?.focus();
return false;
}
if (!parentCityInput || parentCityInput.value.trim().length < 2) {
alert('Please enter your city.');
parentCityInput?.focus();
return false;
}
if (!parentStateInput || parentStateInput.value.trim() === '') {
alert('Please select your state.');
parentStateInput?.focus();
return false;
}
if (!parentZipInput || digitsOnly(parentZipInput.value).length !== 5) {
alert('Please enter a valid 5-digit ZIP code.');
parentZipInput?.focus();
return false;
}
return true;
}
function selectStudentsForEnrollment(ids) {
const wanted = Array.isArray(ids) ? ids.map(Number).filter(id => id > 0) : [];
document.querySelectorAll('[data-student-card]').forEach(card => {
if (card.dataset.selectable !== '1') {
return;
}
const studentId = Number(card.dataset.studentId || 0);
if (wanted.length && !wanted.includes(studentId)) {
return;
}
const input = card.querySelector('[data-enroll-input]');
if (!input) {
return;
}
input.checked = true;
card.classList.add('is-selected');
setStudentFieldsEnabled(card, true);
});
}
function openEnrollmentAtStep(step) {
if (!flowModal || deadlinePassed) {
return false;
}
if (selectedEnrollInputs().length === 0) {
selectStudentsForEnrollment(preselectedStudentIds);
}
if (selectedEnrollInputs().length === 0) {
return false;
}
setStep(step);
flowModal.show();
return true;
}
function syncPolicyAccepted() {
hasAcceptedSchoolPolicy = !!(policyAcceptedCheckbox && policyAcceptedCheckbox.checked);
if (policyAcceptedInput) {
policyAcceptedInput.value = hasAcceptedSchoolPolicy ? '1' : '0';
}
}
function setStudentFieldsEnabled(card, enabled) {
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) {
if (deadlineModal) deadlineModal.show();
return;
}
setStep(0);
flowModal.show();
});
}
document.querySelectorAll('[data-student-card]').forEach(card => {
card.addEventListener('click', function(event) {
if (event.target.closest('input, select, textarea, label')) {
return;
}
if (this.dataset.selectable !== '1') {
return;
}
const input = this.querySelector('[data-enroll-input]');
if (!input) {
return;
}
input.checked = !input.checked;
this.classList.toggle('is-selected', input.checked);
setStudentFieldsEnabled(this, input.checked);
});
});
if (policyAcceptedCheckbox) {
policyAcceptedCheckbox.addEventListener('change', syncPolicyAccepted);
}
if (backButton) {
backButton.addEventListener('click', function() {
setStep(currentStep - 1);
});
}
if (nextButton) {
nextButton.addEventListener('click', function() {
if (currentStep === 0 && selectedEnrollInputs().length === 0) {
alert('Please select at least one student to enroll.');
return;
}
if (currentStep === 0 && !validateSelectedStudentHealth()) {
return;
}
if (currentStep === 1 && !validateParentContact()) {
return;
}
if (currentStep === 2) {
syncPolicyAccepted();
if (!hasAcceptedSchoolPolicy) {
alert('Please read and accept the school policies before continuing.');
return;
}
}
setStep(currentStep + 1);
});
}
if (form) {
form.addEventListener('submit', function(e) {
if (e.submitter && e.submitter.id === 'withdrawSubmitButton') {
selectedEnrollInputs().forEach(input => {
input.checked = false;
const card = input.closest('[data-student-card]');
card?.classList.remove('is-selected');
if (card) {
setStudentFieldsEnabled(card, false);
}
});
}
if (e.submitter && e.submitter.id === 'enrollmentSubmitButton') {
selectedWithdrawInputs().forEach(input => {
input.checked = false;
});
}
const anyEnroll = selectedEnrollInputs().length > 0;
const anyWithdraw = selectedWithdrawInputs().length > 0;
syncPolicyAccepted();
if (!anyEnroll && !anyWithdraw) {
e.preventDefault();
alert('Please select at least one student to enroll or withdraw before submitting.');
return;
}
if (deadlinePassed && anyEnroll) {
e.preventDefault();
if (deadlineModal) deadlineModal.show();
return;
}
if (anyEnroll && !validateSelectedStudentHealth()) {
e.preventDefault();
setStep(0);
if (flowModal) flowModal.show();
return;
}
if (anyEnroll && !validateParentContact()) {
e.preventDefault();
setStep(1);
if (flowModal) flowModal.show();
return;
}
if (anyEnroll && !hasAcceptedSchoolPolicy) {
e.preventDefault();
setStep(2);
if (flowModal) flowModal.show();
return;
}
if (!anyEnroll && anyWithdraw) {
const ok = confirm('Confirm withdrawal request for the selected student(s)?');
if (!ok) {
e.preventDefault();
}
}
});
}
if (parentPhoneInput) {
parentPhoneInput.addEventListener('input', function() {
this.value = formatPhoneDisplay(this.value);
});
}
if (parentZipInput) {
parentZipInput.addEventListener('input', function() {
this.value = digitsOnly(this.value).substring(0, 5);
});
}
if (enrollmentStartStep >= 2 && startButton && !startButton.disabled && !<?= $flashError ? 'true' : 'false' ?>) {
openEnrollmentAtStep(enrollmentStartStep - 1);
}
});
</script>
<?= $this->endSection() ?>