Files
alrahma_sunday_school/app/Views/parent/enroll_classes.php
T
root 0a31aa1393
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 47s
Tests / PHPUnit (push) Successful in 1m16s
fix is_active student flag logic and make moving with enrollment status
2026-08-20 03:11:37 -04:00

836 lines
48 KiB
PHP

<?= $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(4, 1fr);
gap: .5rem;
}
.enrollment-step {
border-bottom: 3px solid #dee2e6;
color: #6c757d;
font-size: .85rem;
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;
}
@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;
}
}
</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 if (session()->getFlashdata('error')): ?>
<div class="alert alert-danger"><?= esc(session()->getFlashdata('error')) ?></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>After submit, enrollment status changes to <strong>admission under review</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, 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">Policies</div>
<div class="enrollment-step" data-step-indicator="2">Tuition</div>
<div class="enrollment-step" data-step-indicator="3">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') ?> and update their information if needed.</div>
<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';
?>
<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-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">Current grade: <?= esc($gradeLabel) ?> &middot; School ID: <?= esc($student['school_id'] ?? 'N/A') ?></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>
</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>
</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>
</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']) ?>
</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">
<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="2">
<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>
<?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>
<?php endif; ?>
</div>
<div class="d-none" data-step-panel="3">
<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">Fees by student</div>
<div id="enrollmentFeeReviewList" class="d-grid gap-2"></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">Registration fee:</span> <strong data-financial-value="registration_fee"><?= esc($money($familyFinancialSummary['registration_fee'] ?? 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">Mandatory fees:</span> <strong data-financial-value="mandatory_fees"><?= esc($money($familyFinancialSummary['mandatory_fees'] ?? 0)) ?></strong></div>
<div class="small"><span class="text-muted">Current-year account balance:</span> <strong data-financial-value="current_balance"><?= esc($money($familyFinancialSummary['current_balance'] ?? 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) to admission review.</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; ?>
<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 finalStep = 3;
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 >= 2) {
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("select[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 name = (firstName + ' ' + lastName).trim() || card?.querySelector('.fw-semibold')?.textContent?.trim() || 'Student';
const metaParts = [];
if (grade) metaParts.push('Registration grade: ' + grade);
if (dob) metaParts.push('DOB: ' + dob);
if (gender) metaParts.push('Gender: ' + gender);
if (schoolId) metaParts.push('School ID: ' + schoolId);
return {
name,
meta: metaParts.join(' - '),
currentGrade,
expectedPlacement,
requiredAction,
};
});
if (!feeReviewList) {
return;
}
if (!cards.length) {
feeReviewList.innerHTML = '<div class="alert alert-warning mb-0">No students selected.</div>';
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';
return '<div class="border rounded p-3">' +
'<div class="d-flex flex-wrap justify-content-between gap-2">' +
'<div><div class="fw-semibold">' + escapeHtml(student.name) + '</div>' +
'<div class="small text-muted">' + escapeHtml(student.meta) + '</div></div>' +
'<div class="text-md-end"><div class="fw-semibold">' + escapeHtml(formatMoney(tuitionFee)) + '</div>' +
'<div class="small text-muted">' + escapeHtml(tier) + '</div></div>' +
'</div>' +
'<div class="row g-2 small mt-2">' +
'<div class="col-md-4"><span class="text-muted">Current grade:</span> ' + escapeHtml(student.currentGrade || 'N/A') + '</div>' +
'<div class="col-md-4"><span class="text-muted">Expected placement:</span> ' + escapeHtml(student.expectedPlacement || 'Pending') + '</div>' +
'<div class="col-md-4"><span class="text-muted">Required action:</span> ' + escapeHtml(student.requiredAction || 'Contact administration') + '</div>' +
'</div>' +
'</div>';
}).join('');
}
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 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;
});
}
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 === 1) {
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 && !hasAcceptedSchoolPolicy) {
e.preventDefault();
setStep(1);
if (flowModal) flowModal.show();
return;
}
if (!anyEnroll && anyWithdraw) {
const ok = confirm('Confirm withdrawal request for the selected student(s)?');
if (!ok) {
e.preventDefault();
}
}
});
}
});
</script>
<?= $this->endSection() ?>