recreate project
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<!-- Flash Messages -->
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success">
|
||||
<?= session()->getFlashdata('success') ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?= session()->getFlashdata('error') ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="container mt-5">
|
||||
<!-- Button to toggle the display of previously saved parent information -->
|
||||
<button class="btn btn-primary mb-4" type="button" data-bs-toggle="collapse" data-bs-target="#savedInfo"
|
||||
aria-expanded="false" aria-controls="savedInfo" id="viewSecondParentBtn">
|
||||
View Parent/AuthorizedUser Information
|
||||
</button>
|
||||
<!-- Collapsible section for the previously saved parent information -->
|
||||
<div class="collapse" id="savedInfo">
|
||||
<div class="card card-body">
|
||||
<h4>Parent/Authorized User Information</h4>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Email</th>
|
||||
<th>Relation</th>
|
||||
<th>Phone</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="parentTable">
|
||||
<!-- Rows will be dynamically populated here -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<form action="<?= base_url('/parent/saveSecondParent') ?>" method="post" id="parentForm">
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<!-- First Name -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="secondParentFirstName" class="form-label fw-bold">First Name <span
|
||||
style="color: red;">*</span></label>
|
||||
<input type="text" class="form-control" id="secondParentFirstName" name="secondParentFirstName"
|
||||
placeholder="First Name" value="<?= old('secondParentFirstName') ?>" pattern="[A-Za-z\s]+"
|
||||
title="Letters only" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Last Name -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="secondParentLastName" class="form-label fw-bold">Last Name <span
|
||||
style="color: red;">*</span></label>
|
||||
<input type="text" class="form-control" id="secondParentLastName" name="secondParentLastName"
|
||||
placeholder="Last Name" value="<?= old('secondParentLastName') ?>" pattern="[A-Za-z\s]+"
|
||||
title="Letters only" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="secondParentEmail" class="form-label fw-bold">Email Address <span
|
||||
style="color: red;">*</span></label>
|
||||
<input type="email" class="form-control" id="secondParentEmail" name="secondParentEmail"
|
||||
placeholder="Email Address" value="<?= old('secondParentEmail') ?>" required>
|
||||
<small id="emailError" class="text-danger"></small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="relationToStudent" class="form-label fw-bold">Relation To Student <span
|
||||
style="color: red;">*</span></label>
|
||||
<select id="relationToStudent" name="relationToStudent" class="form-select" required>
|
||||
<option value="" disabled <?= old('relationToStudent') === null ? 'selected' : '' ?>>Select
|
||||
Relation</option>
|
||||
<option value="Husband" <?= old('relationToStudent') === 'Husband' ? 'selected' : '' ?>>Father
|
||||
</option>
|
||||
<option value="Wife" <?= old('relationToStudent') === 'Wife' ? 'selected' : '' ?>>Mother
|
||||
</option>
|
||||
<option value="Brother" <?= old('relationToStudent') === 'Brother' ? 'selected' : '' ?>>Brother
|
||||
</option>
|
||||
<option value="Sister" <?= old('relationToStudent') === 'Sister' ? 'selected' : '' ?>>Sister
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phone Number with Pattern Validation -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="secondParentCellPhone" class="form-label fw-bold">Phone Number <span
|
||||
style="color: red;">*</span></label>
|
||||
<input type="text" class="form-control" id="secondParentCellPhone" name="secondParentCellPhone"
|
||||
placeholder="Phone Number (xxx)-xxx-xxxx" value="<?= old('secondParentCellPhone') ?>" required>
|
||||
<small class="text-muted">Format: (xxx)-xxx-xxxx</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="row">
|
||||
<div class="col-md-6 d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<?php include(__DIR__ . '/../partials/footer.php'); ?>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- JavaScript for Phone and Email Validation -->
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const phoneInput = document.getElementById('secondParentCellPhone');
|
||||
const emailInput = document.getElementById('secondParentEmail');
|
||||
const firstNameInput = document.getElementById('secondParentFirstName');
|
||||
const lastNameInput = document.getElementById('secondParentLastName');
|
||||
const emailError = document.getElementById('emailError');
|
||||
const nameError = document.createElement('small');
|
||||
nameError.classList.add('text-danger');
|
||||
const lastNameError = document.createElement('small');
|
||||
lastNameError.classList.add('text-danger');
|
||||
|
||||
// Comprehensive domain extension list for validation
|
||||
const validExtensions = [
|
||||
'com', 'net', 'edu', 'org', 'gov', 'mil', 'int',
|
||||
'biz', 'info', 'name', 'pro', 'aero', 'coop', 'museum',
|
||||
'io', 'tech', 'ai', 'app', 'dev', 'xyz', 'store',
|
||||
'us', 'uk', 'ca', 'au', 'de', 'fr', 'it', 'es', 'nl', 'se',
|
||||
'co', 'tv', 'me', 'cc', 'ly', 'in', 'jp', 'cn', 'br', 'ru'
|
||||
];
|
||||
|
||||
// Real-time validation for first and last names (no numbers allowed)
|
||||
const namePattern = /^[a-zA-Z\s]+$/;
|
||||
|
||||
function validateName(input, errorElement, fieldName) {
|
||||
if (!namePattern.test(input.value)) {
|
||||
errorElement.textContent = `Please enter a valid ${fieldName} without numbers.`;
|
||||
input.insertAdjacentElement('afterend', errorElement);
|
||||
} else {
|
||||
errorElement.textContent = '';
|
||||
}
|
||||
}
|
||||
|
||||
firstNameInput.addEventListener('input', function() {
|
||||
validateName(firstNameInput, nameError, 'first name');
|
||||
});
|
||||
|
||||
lastNameInput.addEventListener('input', function() {
|
||||
validateName(lastNameInput, lastNameError, 'last name');
|
||||
});
|
||||
|
||||
// Phone number input formatting
|
||||
phoneInput.addEventListener('input', function(e) {
|
||||
let input = phoneInput.value.replace(/\D/g, ''); // Remove non-digit characters
|
||||
|
||||
if (input.length > 3 && input.length <= 6) {
|
||||
input = `(${input.substring(0, 3)})-${input.substring(3)}`;
|
||||
} else if (input.length > 6) {
|
||||
input = `(${input.substring(0, 3)})-${input.substring(3, 6)}-${input.substring(6, 10)}`;
|
||||
} else if (input.length > 0) {
|
||||
input = `(${input}`;
|
||||
}
|
||||
|
||||
phoneInput.value = input;
|
||||
});
|
||||
|
||||
// Email validation
|
||||
emailInput.addEventListener('input', function() {
|
||||
const emailValue = emailInput.value;
|
||||
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
const domainExtension = emailValue.split('.').pop(); // Get the domain extension
|
||||
|
||||
if (emailValue && !emailPattern.test(emailValue)) {
|
||||
emailError.textContent = 'Please enter a valid email address.';
|
||||
} else if (domainExtension && !validExtensions.includes(domainExtension)) {
|
||||
emailError.textContent =
|
||||
'Please enter an email with a valid domain extension (e.g., .com, .net, .edu).';
|
||||
} else {
|
||||
emailError.textContent = ''; // Clear error message if email is valid
|
||||
}
|
||||
});
|
||||
|
||||
// Form submission validation
|
||||
document.getElementById('parentForm').addEventListener('submit', function(e) {
|
||||
const phoneValue = phoneInput.value;
|
||||
const emailValue = emailInput.value;
|
||||
const domainExtension = emailValue.split('.').pop();
|
||||
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
const phonePattern = /^\(\d{3}\)-\d{3}-\d{4}$/;
|
||||
|
||||
// Ensure no numbers in the first or last name
|
||||
if (!namePattern.test(firstNameInput.value)) {
|
||||
e.preventDefault();
|
||||
alert('Please enter a valid first name without numbers.');
|
||||
}
|
||||
|
||||
if (!namePattern.test(lastNameInput.value)) {
|
||||
e.preventDefault();
|
||||
alert('Please enter a valid last name without numbers.');
|
||||
}
|
||||
|
||||
if (!phonePattern.test(phoneValue)) {
|
||||
e.preventDefault();
|
||||
alert('Please enter a valid phone number in the format (xxx)-xxx-xxxx.');
|
||||
}
|
||||
|
||||
if (!emailPattern.test(emailValue)) {
|
||||
e.preventDefault();
|
||||
alert('Please enter a valid email address.');
|
||||
} else if (!validExtensions.includes(domainExtension)) {
|
||||
e.preventDefault();
|
||||
alert('Please enter an email with a valid domain extension (e.g., .com, .net, .edu).');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.getElementById('viewSecondParentBtn').addEventListener('click', function() {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', '<?= base_url('/parent/viewSecondParent') ?>', true);
|
||||
|
||||
xhr.onload = function() {
|
||||
console.log('Response:', xhr.responseText); // Debugging: Log the raw response
|
||||
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
|
||||
if (response.error) {
|
||||
alert(response.error); // Handle error messages
|
||||
return;
|
||||
}
|
||||
|
||||
const savedParent = response.savedParent;
|
||||
|
||||
// Clear existing rows in the table
|
||||
const parentTable = document.getElementById('parentTable');
|
||||
parentTable.innerHTML = ''; // Clear previous data
|
||||
|
||||
// Populate the table with each entry in savedParent
|
||||
savedParent.forEach(parent => {
|
||||
const row = `
|
||||
<tr>
|
||||
<td>${parent.firstName}</td>
|
||||
<td>${parent.lastName}</t>
|
||||
<td>${parent.email}</td>
|
||||
<td>${parent.relation}</td>
|
||||
<td>${parent.phone}</td>
|
||||
<td>${parent.status || 'N/A'}</td> <!-- Status for authorized users -->
|
||||
</tr>
|
||||
`;
|
||||
parentTable.innerHTML += row;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error parsing JSON response:', error);
|
||||
}
|
||||
} else {
|
||||
console.error('Failed to load parent and authorized user information. Status:', xhr.status);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function() {
|
||||
console.error('An error occurred while fetching parent and authorized user information.');
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,139 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<nav class="col-md-3 col-lg-2 d-md-block bg-light sidebar">
|
||||
<div class="sidebar-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">
|
||||
<i class="bi bi-house-door"></i>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/attendance">
|
||||
<i class="bi bi-calendar-check"></i>
|
||||
Attendance
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/register_kid_form">
|
||||
<i class="bi bi-person-plus"></i>
|
||||
Register Kids
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/enroll_classes">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
Enroll in Classes
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/payment">
|
||||
<i class="bi bi-credit-card"></i>
|
||||
Payment
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/messages">
|
||||
<i class="bi bi-chat-dots"></i>
|
||||
Messages
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/support">
|
||||
<i class="bi bi-life-preserver"></i>
|
||||
Support
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="calendar">
|
||||
<i class="bi bi-calendar"></i>
|
||||
Calendar
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/contact">
|
||||
<i class="bi bi-telephone"></i>
|
||||
Contact Us
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/scores">
|
||||
<i class="bi bi-clipboard-data"></i>
|
||||
Grades
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
|
||||
<div class="pt-3 pb-2 mb-3 border-bottom" style="margin-left: -2in;">
|
||||
<h2>Assignment</h2>
|
||||
<h5 class="h5 mt-2">Enroll your kids in the available classes for the upcoming term.</h5>
|
||||
</div>
|
||||
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success"><?= session()->getFlashdata('success') ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-danger"><?= session()->getFlashdata('error') ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="table-responsive">
|
||||
<form action="<?= base_url('/parent/enroll_classes_handler') ?>" method="post">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Select</th>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Age</th>
|
||||
<th>Gender</th>
|
||||
<th>Grade</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (!empty($students)): ?>
|
||||
<?php foreach ($students as $student): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" name="enroll[]" value="<?= $student['student_id'] ?>">
|
||||
</td>
|
||||
<td><?= $student['firstname'] ?></td>
|
||||
<td><?= $student['lastname'] ?></td>
|
||||
<td><?= $student['age'] ?></td>
|
||||
<td><?= $student['gender'] ?></td>
|
||||
<td><?= $student['grade'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="6">No students found. Please register your kids first.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="form-group">
|
||||
<label for="class_section_id">Select Class</label>
|
||||
<select class="form-control" id="class_section_id" name="class_section_id" required>
|
||||
<option value="">Select Class</option>
|
||||
<?php foreach ($classes as $class): ?>
|
||||
<option value="<?= $class['class_section_id'] ?>"><?= $class['class_name'] ?>
|
||||
(<?= $class['schedule'] ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Enroll Selected Students</button>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container my-5">
|
||||
<h3 class="text-center text-success" style="font-family: Arial, sans-serif;">Attendance Record</h2>
|
||||
</div>
|
||||
<!-- Filter Form -->
|
||||
|
||||
|
||||
<form action="" method="get" class="form-inline">
|
||||
<div class="d-flex align-items-center">
|
||||
<select name="school_year" id="school_year" class="form-control me-3"> <!-- Added me-3 (right margin) -->
|
||||
<?php foreach ($schoolYears as $year): ?>
|
||||
<option value="<?= esc($year['school_year']) ?>" <?= $selectedYear === $year['school_year'] ? 'selected' : '' ?>>
|
||||
<?= esc($year['school_year']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-success">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Error Message -->
|
||||
<?php if (isset($error)): ?>
|
||||
<div class="alert alert-danger"><?= esc($error) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Attendance Table (one record per row; no regrouping) -->
|
||||
<?php if (!empty($attendance)): ?>
|
||||
<table class="table table-striped table-bordered mt-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Date</th>
|
||||
<th>Status</th>
|
||||
<th>Reason</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($attendance as $row): ?>
|
||||
<?php $status = strtolower(trim((string)($row['status'] ?? ''))); ?>
|
||||
<?php if ($status === 'absent' || $status === 'late'): ?>
|
||||
<tr>
|
||||
<td><?= esc($row['firstname'] ?? '') ?></td>
|
||||
<td><?= esc($row['lastname'] ?? '') ?></td>
|
||||
<td><?= esc(!empty($row['date']) ? local_date($row['date'], 'm-d-Y') : '') ?></td>
|
||||
<td><?= esc($row['status'] ?? '') ?></td>
|
||||
<td><?= esc($row['reason'] ?? '') ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info mb-3 d-inline-block">No attendance records found for the selected school year.</div>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,76 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container-xxl py-2">
|
||||
<div class="container">
|
||||
<h3 class="text-center text-danger mt-4 mb-3" style="font-family: Arial, sans-serif;">
|
||||
Flip your phone for a zoomed out view of the calendar.
|
||||
</h3>
|
||||
|
||||
<div class="d-flex align-items-center gap-3 mb-3">
|
||||
<strong>Legend:</strong>
|
||||
<span class="d-inline-flex align-items-center"><span style="display:inline-block;width:12px;height:12px;border-radius:3px;background:#3788d8;border:1px solid rgba(0,0,0,.2);margin-right:6px"></span>General Event</span>
|
||||
<span class="d-inline-flex align-items-center"><span style="display:inline-block;width:12px;height:12px;border-radius:3px;background:#ffc107;border:1px solid rgba(0,0,0,.2);margin-right:6px"></span>No School Day</span>
|
||||
</div>
|
||||
<div class="main-content">
|
||||
<div id="calendar-container">
|
||||
<div id="calendar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
<?= $this->section('scripts') ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const calendarEl = document.getElementById('calendar');
|
||||
const isMobile = window.innerWidth <= 576;
|
||||
|
||||
const calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
initialView: isMobile ? 'listWeek' : 'dayGridMonth',
|
||||
height: 'auto',
|
||||
contentHeight: 'auto',
|
||||
expandRows: true,
|
||||
events: <?= json_encode($events) ?>,
|
||||
|
||||
eventDidMount: function(info) {
|
||||
if (info.event.extendedProps.description) {
|
||||
$(info.el).tooltip({
|
||||
title: info.event.extendedProps.description,
|
||||
placement: 'top',
|
||||
trigger: 'hover',
|
||||
container: 'body'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
eventContent: function(arg) {
|
||||
const event = arg.event;
|
||||
const bg = event.extendedProps.backgroundColor || '#3788d8';
|
||||
return {
|
||||
html: `
|
||||
<div style="
|
||||
background-color: ${bg};
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font-size: 0.8rem;
|
||||
text-align: center;">
|
||||
${event.title}
|
||||
</div>`
|
||||
};
|
||||
},
|
||||
|
||||
windowResize: function(view) {
|
||||
if (window.innerWidth <= 576 && calendar.view.type !== 'listWeek') {
|
||||
calendar.changeView('listWeek');
|
||||
} else if (window.innerWidth > 576 && calendar.view.type !== 'dayGridMonth') {
|
||||
calendar.changeView('dayGridMonth');
|
||||
}
|
||||
calendar.updateSize();
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
window.calendar = calendar;
|
||||
});
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,86 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container py-4">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3 flex-wrap gap-2">
|
||||
<div>
|
||||
<h3 class="mb-0">Class Progress</h3>
|
||||
<div class="text-muted">Review the weekly reports your child’s teachers submit.</div>
|
||||
</div>
|
||||
<div class="text-end text-muted small">
|
||||
Reports are grouped by Sunday; click any row to read the full details.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (! $hasSections): ?>
|
||||
<div class="alert alert-info">
|
||||
We couldn’t find any current enrollment for your account. Once your child is assigned to a Sunday class, their teacher’s progress reports will appear here.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (empty($reportGroups)): ?>
|
||||
<div class="alert alert-secondary">No reports submitted yet.</div>
|
||||
<?php else: ?>
|
||||
<div class="card shadow-sm">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Week</th>
|
||||
<th>Subjects</th>
|
||||
<th class="text-end">Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($reportGroups as $group): ?>
|
||||
<?php
|
||||
$start = $group['week_start'] ?? '';
|
||||
$end = $group['week_end'] ?? '';
|
||||
$weekLabel = $start ? date('M d, Y', strtotime($start)) : '-';
|
||||
if ($end) {
|
||||
$weekLabel .= ' – ' . date('M d, Y', strtotime($end));
|
||||
}
|
||||
$reports = $group['reports'] ?? [];
|
||||
$exampleReport = $reports ? reset($reports) : null;
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-semibold"><?= esc($weekLabel) ?></div>
|
||||
<?php if (!empty($group['class_section_name'])): ?>
|
||||
<div class="text-muted small">Class: <?= esc($group['class_section_name']) ?></div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<?php foreach ($subjectSections as $slug => $section): ?>
|
||||
<?php
|
||||
$subjectName = $section['db_subject'] ?? $section['label'] ?? $slug;
|
||||
$report = $reports[$subjectName] ?? null;
|
||||
$statusLabel = $report ? ($report['status_label'] ?? 'Unknown') : 'No submission';
|
||||
$badgeClass = $report ? 'bg-secondary' : 'bg-light text-muted';
|
||||
?>
|
||||
<div class="border rounded-3 p-2">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<strong class="small mb-0"><?= esc($section['label'] ?? $subjectName) ?></strong>
|
||||
<span class="badge <?= esc($badgeClass) ?>"><?= esc($statusLabel) ?></span>
|
||||
</div>
|
||||
<div class="small text-muted">
|
||||
<?= $report ? esc($report['unit_title'] ?: '-') : 'No submission' ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?php if ($exampleReport): ?>
|
||||
<a href="<?= base_url('parent/progress/view/' . $exampleReport['id']) ?>" class="btn btn-sm btn-outline-primary">View Weekly Details</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,136 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container py-4">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<div>
|
||||
<h3 class="mb-0">Progress Report</h3>
|
||||
<div class="text-muted">
|
||||
<?= esc($row['class_section_name'] ?? '-') ?> • <?= esc($row['week_start'] ?? '-') ?>
|
||||
</div>
|
||||
</div>
|
||||
<a href="<?= base_url('parent/progress') ?>" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$weeklyReports = $weeklyReports ?? [];
|
||||
$subjectSections = $subjectSections ?? [];
|
||||
$reportsBySubject = [];
|
||||
$attachments = [];
|
||||
foreach ($weeklyReports as $report) {
|
||||
$reportsBySubject[$report['subject']] = $report;
|
||||
foreach (($report['attachments'] ?? []) as $attachment) {
|
||||
$attachments[] = [
|
||||
'subject' => $report['subject'] ?? 'Attachment',
|
||||
'attachment' => $attachment,
|
||||
'report_id' => $report['id'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-8">
|
||||
<?php foreach ($subjectSections as $slug => $section): ?>
|
||||
<?php
|
||||
$subjectName = $section['db_subject'] ?? $section['label'] ?? $slug;
|
||||
$isQuran = $subjectName === 'Quran/Arabic';
|
||||
$unitLabel = $isQuran ? 'Surah / Custom Arabic' : 'Unit / Chapter';
|
||||
$homeworkLabel = $isQuran ? 'Arabic Practice / Homework' : 'Assigned Homework';
|
||||
$report = $reportsBySubject[$subjectName] ?? null;
|
||||
?>
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header bg-white d-flex align-items-center justify-content-between">
|
||||
<strong class="mb-0"><?= esc($section['label'] ?? $subjectName) ?></strong>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (! $report): ?>
|
||||
<div class="text-muted">No entry submitted for this subject this week.</div>
|
||||
<?php else: ?>
|
||||
<?php if (!empty($report['materials'])): ?>
|
||||
<div class="mb-2"><strong>Materials:</strong> <?= esc($report['materials']) ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="mb-2"><strong><?= $unitLabel ?>:</strong> <?= esc($report['unit_title'] ?: '-') ?></div>
|
||||
<div class="mb-3">
|
||||
<strong>Activities / Notes</strong>
|
||||
<div class="mt-1"><?= nl2br(esc($report['covered'] ?? '-')) ?></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong><?= $homeworkLabel ?>:</strong>
|
||||
<div class="mt-1"><?= nl2br(esc($report['homework'] ?: '-')) ?></div>
|
||||
</div>
|
||||
<?php if (!empty($report['attachments'])): ?>
|
||||
<div class="mt-3">
|
||||
<strong>Attachments:</strong>
|
||||
<div class="d-flex flex-column gap-2 mt-2">
|
||||
<?php foreach ($report['attachments'] as $attachment): ?>
|
||||
<?php
|
||||
$linkId = $attachment['id'] ?? $report['id'];
|
||||
$link = !empty($attachment['legacy'])
|
||||
? base_url('parent/progress/attachment/' . $linkId)
|
||||
: base_url('parent/progress/attachment-file/' . $linkId);
|
||||
?>
|
||||
<a class="btn btn-sm btn-outline-secondary text-start" href="<?= $link ?>" target="_blank" rel="noreferrer">
|
||||
<?= esc($attachment['name'] ?? 'Attachment') ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header bg-white"><strong>Summary</strong></div>
|
||||
<div class="card-body">
|
||||
<div class="mb-2"><strong>Teacher:</strong> <?= esc($row['teacher_name'] ?? '-') ?></div>
|
||||
<div class="mb-2"><strong>Submitted:</strong> <?= esc($row['created_at'] ? date('M d, Y g:i A', strtotime($row['created_at'])) : '-') ?></div>
|
||||
<?php if (!empty($row['status_label'])): ?>
|
||||
<div><strong>Status:</strong> <?= esc($row['status_label']) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($row['flags'])): ?>
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header bg-white"><strong>Highlights</strong></div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<?php foreach ($row['flags'] as $flag): ?>
|
||||
<span class="badge bg-info text-dark"><?= esc(str_replace('_', ' ', $flag)) ?></span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($attachments)): ?>
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-white"><strong>Attachments</strong></div>
|
||||
<div class="card-body">
|
||||
<?php foreach ($attachments as $entry): ?>
|
||||
<?php
|
||||
$attachment = $entry['attachment'] ?? [];
|
||||
$linkId = $attachment['id'] ?? ($entry['report_id'] ?? null);
|
||||
if (!$linkId) {
|
||||
continue;
|
||||
}
|
||||
$link = !empty($attachment['legacy'])
|
||||
? base_url('parent/progress/attachment/' . $linkId)
|
||||
: base_url('parent/progress/attachment-file/' . $linkId);
|
||||
$label = trim(($entry['subject'] ?? 'Attachment') . ' • ' . ($attachment['name'] ?? 'Attachment'));
|
||||
?>
|
||||
<a class="btn btn-outline-primary w-100 text-start mb-2" href="<?= $link ?>" target="_blank" rel="noreferrer">
|
||||
<?= esc($label) ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,138 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<nav class="col-md-3 col-lg-2 d-md-block bg-light sidebar">
|
||||
<div class="sidebar-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">
|
||||
<i class="bi bi-house-door"></i>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/attendance">
|
||||
<i class="bi bi-calendar-check"></i>
|
||||
Attendance
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/register_kid_form">
|
||||
<i class="bi bi-person-plus"></i>
|
||||
Register Kids
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/enroll_classes">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
Enroll in Classes
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/payment">
|
||||
<i class="bi bi-credit-card"></i>
|
||||
Payment
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/messages">
|
||||
<i class="bi bi-chat-dots"></i>
|
||||
Messages
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/support">
|
||||
<i class="bi bi-life-preserver"></i>
|
||||
Support
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="calendar">
|
||||
<i class="bi bi-calendar"></i>
|
||||
Calendar
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/contact">
|
||||
<i class="bi bi-telephone"></i>
|
||||
Contact Us
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/parent/scores">
|
||||
<i class="bi bi-clipboard-data"></i>
|
||||
Grades
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
|
||||
<div class="pt-3 pb-2 mb-3 border-bottom" style="margin-left: -2in;">
|
||||
<h2>Enroll in Classes</h2>
|
||||
<h5 class="h5 mt-2">Enroll your kids in the available classes for the upcoming term.</h5>
|
||||
</div>
|
||||
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success"><?= session()->getFlashdata('success') ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-danger"><?= session()->getFlashdata('error') ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="table-responsive">
|
||||
<form action="<?= base_url('/parent/enroll_classes_handler') ?>" method="post">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Select</th>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Age</th>
|
||||
<th>Gender</th>
|
||||
<th>Grade</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (!empty($students)): ?>
|
||||
<?php foreach ($students as $student): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" name="enroll[]" value="<?= $student['student_id'] ?>">
|
||||
</td>
|
||||
<td><?= $student['firstname'] ?></td>
|
||||
<td><?= $student['lastname'] ?></td>
|
||||
<td><?= $student['age'] ?></td>
|
||||
<td><?= $student['gender'] ?></td>
|
||||
<td><?= $student['grade'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="6">No students found. Please register your kids first.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="form-group">
|
||||
<label for="class_section_id">Select Class</label>
|
||||
<select class="form-control" id="class_section_id" name="class_section_id" required>
|
||||
<option value="">Select Class</option>
|
||||
<?php foreach ($classes as $class): ?>
|
||||
<option value="<?= $class['class_section_id'] ?>"><?= $class['class_name'] ?>
|
||||
(<?= $class['schedule'] ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Enroll Selected Students</button>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,112 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container-xxl bg-white p-0">
|
||||
<!-- Contact Start -->
|
||||
<div class="container-xxl py-5">
|
||||
<div class="container">
|
||||
<div class="text-center mx-auto mb-5 wow fadeInUp" data-wow-delay="0.1s" style="max-width: 600px;">
|
||||
<h1 class="mb-3">Get In Touch</h1>
|
||||
<p>Get in touch with us today to learn more about our programs and how you can get involved.</p>
|
||||
</div>
|
||||
<div class="row g-4 mb-5">
|
||||
<div class="col-md-6 col-lg-4 text-center wow fadeInUp" data-wow-delay="0.1s">
|
||||
<div class="bg-light rounded-circle d-inline-flex align-items-center justify-content-center mb-4"
|
||||
style="width: 75px; height: 75px;">
|
||||
<i class="fa fa-map-marker-alt fa-2x text-success"></i>
|
||||
</div>
|
||||
<h6>5 Courthouse Lane, Chelmsford, MA 01824</h6>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-4 text-center wow fadeInUp" data-wow-delay="0.3s">
|
||||
<div class="bg-light rounded-circle d-inline-flex align-items-center justify-content-center mb-4"
|
||||
style="width: 75px; height: 75px;">
|
||||
<i class="fa fa-envelope-open fa-2x text-success"></i>
|
||||
</div>
|
||||
<h6>alrahma.isgl@gmail.com</h6>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-4 text-center wow fadeInUp" data-wow-delay="0.5s">
|
||||
<div class="bg-light rounded-circle d-inline-flex align-items-center justify-content-center mb-4"
|
||||
style="width: 75px; height: 75px;">
|
||||
<i class="fa fa-phone-alt fa-2x text-success"></i>
|
||||
</div>
|
||||
<h6>+1 978-364-0219</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-light rounded">
|
||||
<div class="row g-0">
|
||||
<div class="col-lg-6 wow fadeIn" data-wow-delay="0.1s">
|
||||
<div class="h-100 d-flex flex-column justify-content-center p-5">
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success">
|
||||
<?= session()->getFlashdata('success') ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($validation)): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?= $validation->listErrors() ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="<?= base_url('/parent/contact/submit') ?>" method="post">
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-6">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control border-0" id="name" name="name"
|
||||
placeholder="Your Name" value="<?= set_value('name') ?>" required>
|
||||
<label for="name">Your Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="form-floating">
|
||||
<input type="email" class="form-control border-0" id="email"
|
||||
name="email" placeholder="Your Email"
|
||||
value="<?= set_value('email') ?>" required>
|
||||
<label for="email">Your Email</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control border-0" id="subject"
|
||||
name="subject" placeholder="Subject"
|
||||
value="<?= set_value('subject') ?>" required>
|
||||
<label for="subject">Subject</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-floating">
|
||||
<textarea class="form-control border-0"
|
||||
placeholder="Leave a message here" id="message" name="message"
|
||||
style="height: 100px"
|
||||
required><?= set_value('message') ?></textarea>
|
||||
<label for="message">Message</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button class="btn btn-success w-100 py-3" type="submit">Send
|
||||
Message</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 wow fadeIn" data-wow-delay="0.5s" style="min-height: 400px;">
|
||||
<div class="position-relative h-100">
|
||||
<iframe class="position-relative rounded w-100 h-100"
|
||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2949.902891223497!2d-71.3606721845427!3d42.59682637917086!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89e3a489bb344a85%3A0xeaba1b29330726cb!2s5%20Courthouse%20Ln%2C%20Chelmsford%2C%20MA%2001824%2C%20USA!5e0!3m2!1sen!2sbd!4v1627993075161!5m2!1sen!2sbd"
|
||||
frameborder="0" style="min-height: 400px; border:0;" allowfullscreen=""
|
||||
aria-hidden="false" tabindex="0"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Contact End -->
|
||||
|
||||
<!-- Back to Top -->
|
||||
<a href="#" class="btn btn-lg btn-success btn-lg-square back-to-top"><i class="bi bi-arrow-up"></i></a>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
$fullName = trim($contact['emergency_contact_name'] ?? '');
|
||||
$nameParts = explode(' ', $fullName, 2);
|
||||
$firstName = $nameParts[0] ?? '';
|
||||
$lastName = $nameParts[1] ?? '';
|
||||
?>
|
||||
|
||||
<div class="modal fade" id="editEmergencyContact<?= $contact['id'] ?>" tabindex="-1" aria-labelledby="editEmergencyContactLabel<?= $contact['id'] ?>" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<form method="post" action="<?= site_url('parent/edit_emergency_contact/' . $contact['id']) ?>" onsubmit="return validateEmergencyContactForm(<?= $contact['id'] ?>)">
|
||||
<?= csrf_field() ?>
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editEmergencyContactLabel<?= $contact['id'] ?>">Edit Emergency Contact</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<!-- First Name -->
|
||||
<div class="form-group mb-3">
|
||||
<label for="emergencyFirstName<?= $contact['id'] ?>">First Name</label>
|
||||
<input type="text"
|
||||
id="emergencyFirstName<?= $contact['id'] ?>"
|
||||
name="emergency_first_name"
|
||||
class="form-control"
|
||||
value="<?= esc($firstName) ?>"
|
||||
required
|
||||
maxlength="30"
|
||||
title="Only letters, spaces, hyphens, and apostrophes allowed">
|
||||
</div>
|
||||
|
||||
<!-- Last Name -->
|
||||
<div class="form-group mb-3">
|
||||
<label for="emergencyLastName<?= $contact['id'] ?>">Last Name</label>
|
||||
<input type="text"
|
||||
id="emergencyLastName<?= $contact['id'] ?>"
|
||||
name="emergency_last_name"
|
||||
class="form-control"
|
||||
value="<?= esc($lastName) ?>"
|
||||
required
|
||||
maxlength="30"
|
||||
title="Only letters, spaces, hyphens, and apostrophes allowed">
|
||||
</div>
|
||||
|
||||
<!-- Phone -->
|
||||
<div class="form-group mb-3">
|
||||
<label for="cellPhone<?= $contact['id'] ?>">Cell Phone</label>
|
||||
<input type="tel"
|
||||
id="cellPhone<?= $contact['id'] ?>"
|
||||
name="cellphone"
|
||||
class="form-control"
|
||||
value="<?= esc($contact['cellphone']) ?>"
|
||||
required
|
||||
maxlength="14"
|
||||
inputmode="numeric"
|
||||
title="Enter a valid 10-digit phone number">
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="form-group mb-3">
|
||||
<label for="email<?= $contact['id'] ?>">Email</label>
|
||||
<input type="email"
|
||||
id="email<?= $contact['id'] ?>"
|
||||
name="email"
|
||||
class="form-control"
|
||||
value="<?= esc($contact['email'] ?? '') ?>"
|
||||
required
|
||||
maxlength="50"
|
||||
title="Enter a valid email address">
|
||||
</div>
|
||||
|
||||
<!-- Relation -->
|
||||
<div class="form-group mb-3">
|
||||
<label for="relation<?= $contact['id'] ?>">Relation</label>
|
||||
<input type="text"
|
||||
id="relation<?= $contact['id'] ?>"
|
||||
name="relation"
|
||||
class="form-control"
|
||||
value="<?= esc($contact['relation']) ?>"
|
||||
required
|
||||
maxlength="30"
|
||||
title="Only letters, spaces, hyphens, and apostrophes allowed">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
// add this *inside* your foreach loop
|
||||
$modalId = "editStudentModal{$student['id']}";
|
||||
$formId = "studentEditForm{$student['id']}";
|
||||
$actionUrl = site_url('parent/edit_student/' . $student['id']);
|
||||
?>
|
||||
<!--–––– MODAL ––––-->
|
||||
<div class="modal fade" id="<?= $modalId ?>" tabindex="-1" aria-labelledby="<?= $modalId ?>Label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<!-- one form only -->
|
||||
<form method="post"
|
||||
action="<?= $actionUrl ?>"
|
||||
id="<?= $formId ?>"
|
||||
class="student-edit-form needs-live-validation">
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="<?= $modalId ?>Label">
|
||||
Edit Student: <?= esc($student['firstname'] . ' ' . $student['lastname']) ?>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<!-- First / Last -->
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">First Name</label>
|
||||
<input type="text" name="firstname" class="form-control" value="<?= esc($student['firstname']) ?>" maxlength="30" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Last Name</label>
|
||||
<input type="text" name="lastname" class="form-control" value="<?= esc($student['lastname']) ?>" maxlength="30" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DOB / Gender -->
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Date of Birth</label>
|
||||
<input type="date" name="dob" class="form-control" value="<?= esc($student['dob']) ?>" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Gender</label>
|
||||
<select name="gender" class="form-select" required>
|
||||
<option value="">-- Select --</option>
|
||||
<option value="Male" <?= strtolower($student['gender']) === 'male' ? 'selected' : '' ?>>Male</option>
|
||||
<option value="Female" <?= strtolower($student['gender']) === 'female' ? 'selected' : '' ?>>Female</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Allergies / Conditions -->
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Allergies (comma-separated)</label>
|
||||
<input type="text" name="allergies" class="form-control"
|
||||
value="<?= esc(is_array($student['allergies']) ? implode(', ', $student['allergies']) : $student['allergies']) ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Medical Conditions (comma-separated)</label>
|
||||
<input type="text" name="medical_conditions" class="form-control"
|
||||
value="<?= esc(is_array($student['medical_conditions']) ? implode(', ', $student['medical_conditions']) : $student['medical_conditions']) ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Consent / Grade -->
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Photo Consent</label>
|
||||
<select name="photo_consent" class="form-select" required>
|
||||
<option value="">-- Select --</option>
|
||||
<option value="1" <?= $student['photo_consent'] ? 'selected' : '' ?>>Yes</option>
|
||||
<option value="0" <?= !$student['photo_consent'] ? 'selected' : '' ?>>No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Registration Grade</label>
|
||||
<input type="text" name="registration_grade" class="form-control" value="<?= esc($student['registration_grade']) ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="fas fa-save"></i> Save Changes
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,254 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container my-5">
|
||||
<h3 class="text-center text-success" style="font-family: Arial, sans-serif;">Enroll in Classes</h3>
|
||||
</div>
|
||||
|
||||
<!-- School Year Filter -->
|
||||
<form action="<?= base_url('/parent/enroll_classes') ?>" method="get" class="form-inline mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<select name="school_year" id="school_year" class="form-control me-3">
|
||||
<?php foreach ($schoolYears as $year): ?>
|
||||
<option value="<?= esc($year['school_year']) ?>" <?= $selectedYear === $year['school_year'] ? 'selected' : '' ?>>
|
||||
<?= esc($year['school_year']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-success">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
// Put this near the very top of the file (before output), or right after the extend/section lines.
|
||||
$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;
|
||||
$deadlineISO = $deadlineObj->format('Y-m-d\TH:i:sP'); // for JS
|
||||
?>
|
||||
<!-- Registration Info -->
|
||||
<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>
|
||||
<li>Last Day for Enrollment is <strong><?= esc(local_date($lastDayOfRegistration, 'm-d-Y')) ?></strong>.</li>
|
||||
<li>Once you click "Save", the enrollment status will change 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">
|
||||
<?= csrf_field() ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>School ID</th>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Age</th>
|
||||
<th>Gender</th>
|
||||
<th>Grade</th>
|
||||
<th>Enroll</th>
|
||||
<th>Withdraw</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($students as $index => $student): ?>
|
||||
<tr>
|
||||
<td><?= $index + 1 ?></td>
|
||||
<td><?= esc($student['school_id'] ?? 'N/A') ?></td>
|
||||
<td><?= esc($student['firstname'] ?? 'N/A') ?></td>
|
||||
<td><?= esc($student['lastname'] ?? 'N/A') ?></td>
|
||||
<td><?= esc($student['age'] ?? 'N/A') ?></td>
|
||||
<td><?= esc($student['gender'] ?? 'N/A') ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$section = $student['class_section'] ?? null;
|
||||
echo $section
|
||||
? esc(preg_replace_callback('/\byouth\b/i', fn($m) => ucfirst(strtolower($m[0])), $section))
|
||||
: 'Not Assigned';
|
||||
?>
|
||||
</td>
|
||||
|
||||
<!-- Enroll Checkbox -->
|
||||
<td>
|
||||
<?php if ($student['enrollment_status'] === 'not enrolled'): ?>
|
||||
<?php $disableEnrollUI = $deadlinePassed || !$isEditable; ?>
|
||||
<input type="checkbox"
|
||||
name="enroll[]"
|
||||
value="<?= esc($student['id']) ?>"
|
||||
<?= $disableEnrollUI ? 'disabled' : '' ?>>
|
||||
<?php elseif (in_array($student['enrollment_status'], ['enrolled', 'admission under review', 'payment pending', 'withdraw under review'])): ?>
|
||||
<input type="checkbox" checked disabled>
|
||||
<?php else: ?>
|
||||
<input type="checkbox" disabled>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<!-- Withdraw Checkbox -->
|
||||
<td>
|
||||
<?php if ($student['enrollment_status'] === 'enrolled'): ?>
|
||||
<input type="checkbox" name="withdraw[]" value="<?= esc($student['id']) ?>" <?= !$isEditable ? 'disabled' : '' ?>>
|
||||
<?php elseif ($student['enrollment_status'] === 'withdrawn'): ?>
|
||||
<input type="checkbox" checked disabled>
|
||||
<?php else: ?>
|
||||
<input type="checkbox" disabled>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<!-- Status -->
|
||||
<td>
|
||||
<?php
|
||||
$status = strtolower(trim($student['enrollment_status'] ?? ''));
|
||||
|
||||
switch ($status) {
|
||||
case 'admission under review':
|
||||
echo '<span class="badge bg-primary">admission under review</span>';
|
||||
break;
|
||||
case 'payment pending':
|
||||
echo '<span class="badge bg-warning text-dark">payment pending</span>';
|
||||
break;
|
||||
case 'enrolled':
|
||||
echo '<span class="badge bg-success">enrolled</span>';
|
||||
break;
|
||||
case 'withdraw under review':
|
||||
echo '<span class="badge bg-warning text-dark">withdraw under review</span>';
|
||||
break;
|
||||
case 'refund pending':
|
||||
echo '<span class="badge bg-info text-dark">refund pending</span>';
|
||||
break;
|
||||
case 'withdrawn':
|
||||
echo '<span class="badge bg-danger">withdrawn</span>';
|
||||
break;
|
||||
case 'waitlist':
|
||||
echo '<span class="badge bg-secondary">waitlist</span>'; // lighter and neutral
|
||||
break;
|
||||
case 'denied':
|
||||
echo '<span class="badge bg-danger">denied</span>'; // red stands out clearly
|
||||
break;
|
||||
case 'not enrolled':
|
||||
echo '<span class="badge bg-light text-dark">not enrolled</span>'; // very neutral
|
||||
break;
|
||||
default:
|
||||
echo '<span class="badge bg-light text-dark">unknown</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Save Button -->
|
||||
<?php
|
||||
$today = local_date(utc_now(), 'Y-m-d');
|
||||
$disableDueToDate = ($today >= $lastDayOfRegistration);
|
||||
// Allow submit for withdrawals even after deadline; keep editability guard only
|
||||
$disableSave = !$isEditable;
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-center">
|
||||
<button type="submit"
|
||||
class="btn btn-lg btn-success <?= $disableSave ? 'disabled' : '' ?>"
|
||||
<?= $disableSave ? 'disabled' : '' ?>
|
||||
title="<?php
|
||||
if (!$isEditable) {
|
||||
echo 'Editing is not allowed for this record.';
|
||||
}
|
||||
?>">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<p>No students found for the selected school year. Please register your kids first.</p>
|
||||
<?php endif; ?>
|
||||
<!-- Enrollment Deadline Modal -->
|
||||
<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), but new enrollments are no longer accepted.
|
||||
<br><br>
|
||||
If you believe this is an error, please contact the school office.
|
||||
</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() {
|
||||
// Values from PHP
|
||||
const deadlinePassed = <?= $deadlinePassed ? 'true' : 'false' ?>;
|
||||
const enrollmentDeadline = new Date("<?= esc($deadlineISO) ?>");
|
||||
|
||||
// Bootstrap Modal
|
||||
const modalEl = document.getElementById('deadlineModal');
|
||||
const deadlineModal = modalEl ? new bootstrap.Modal(modalEl) : null;
|
||||
const showDeadlineModal = () => {
|
||||
if (deadlineModal) deadlineModal.show();
|
||||
};
|
||||
|
||||
// The enrollment form
|
||||
const form = document.querySelector("form[action*='enroll_classes_handler']");
|
||||
|
||||
// 1) Block clicking "enroll" checkboxes after deadline
|
||||
document.querySelectorAll("input[name='enroll[]']").forEach(cb => {
|
||||
cb.addEventListener("click", function(e) {
|
||||
if (deadlinePassed) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
this.checked = false;
|
||||
showDeadlineModal();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 2) Prevent submission if any enroll[] is checked after deadline
|
||||
if (form) {
|
||||
form.addEventListener("submit", function(e) {
|
||||
const anyBoxesChecked = form.querySelectorAll("input[name='enroll[]']:checked").length > 0;
|
||||
const anyWithdrawChecked = form.querySelectorAll("input[name='withdraw[]']:checked").length > 0;
|
||||
|
||||
if (!anyBoxesChecked && !anyWithdrawChecked) {
|
||||
e.preventDefault();
|
||||
alert("Please select at least one student to enroll or withdraw before saving.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (deadlinePassed && anyBoxesChecked) {
|
||||
e.preventDefault();
|
||||
showDeadlineModal();
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) If only withdrawals are selected, ask for a quick confirmation
|
||||
if (!anyBoxesChecked && anyWithdrawChecked) {
|
||||
const ok = confirm('Confirm withdrawal request for the selected student(s)?');
|
||||
if (!ok) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
|
||||
<div class="alert alert-danger mt-4">
|
||||
<h4 class="alert-heading">Failure!</h4>
|
||||
<p>There was an issue enrolling the students. Please try again later.</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
|
||||
<div class="alert alert-success mt-4">
|
||||
<h4 class="alert-heading">Success!</h4>
|
||||
<p>The student(s) has/have been successfully enrolled.</p>
|
||||
<p>You will be redirected to the enroll page shortly...</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<script>
|
||||
setTimeout(function() {
|
||||
window.location.href = "<?= base_url('/parent/enroll_classes'); ?>";
|
||||
}, 5000); // 2500 milliseconds = 2.5 seconds
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container my-5">
|
||||
<h3 class="text-center text-success" style="font-family: Arial, sans-serif;">Events
|
||||
<span class="badge bg-info"><?= count($activeEvents) ?></span>
|
||||
</h3>
|
||||
|
||||
<!-- Flash messages -->
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success">
|
||||
<?= session()->getFlashdata('success') ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?= session()->getFlashdata('error') ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (empty($activeEvents)): ?>
|
||||
<div class="alert alert-info mb-3 d-inline-block">
|
||||
There are no active events at this time.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($activeEvents as $event): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
|
||||
<!-- Event Title -->
|
||||
<h5 class="card-title">
|
||||
<?= esc($event['event_name']) ?>
|
||||
<small class="text-muted">(Expires: <?= esc(!empty($event['expiration_date']) ? local_date($event['expiration_date'], 'm-d-Y') : '') ?>)</small>
|
||||
</h5>
|
||||
|
||||
<!-- Image -->
|
||||
<div class="text-center mb-3">
|
||||
<?php if ($event['flyer']): ?>
|
||||
<img src="<?= base_url('uploads/' . $event['flyer']) ?>" class="img-fluid" alt="Event Flyer">
|
||||
<?php else: ?>
|
||||
<div class="text-muted">No Flyer</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Event Description -->
|
||||
<p class="card-text"><?= esc($event['description']) ?></p>
|
||||
|
||||
<!-- Participation Table -->
|
||||
<form method="post" action="<?= site_url('parent/updateParticipation') ?>">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="event_id" value="<?= $event['id'] ?>">
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Student First Name</th>
|
||||
<th>Student Last Name</th>
|
||||
<th class="text-center">Participate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($yourStudents as $student): ?>
|
||||
<?php
|
||||
$key = $student['id'] . ':' . $event['id'];
|
||||
$current = $charges[$key]['participation'] ?? '';
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc($student['firstname']) ?></td>
|
||||
<td><?= esc($student['lastname']) ?></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-inline-flex align-items-center gap-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="participation[<?= $key ?>]" value="yes"
|
||||
<?= $current === 'yes' ? 'checked' : '' ?>>
|
||||
<label class="form-check-label">Yes</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="participation[<?= $key ?>]" value="no"
|
||||
<?= $current === 'no' ? 'checked' : '' ?>>
|
||||
<label class="form-check-label">No</label>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-2">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,173 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?php
|
||||
// ---- Local helper: parse DB date/datetime safely and convert to display TZ ----
|
||||
if (!function_exists('parseDbDateTime')) {
|
||||
/**
|
||||
* @param mixed $raw String "Y-m-d H:i:s" or "Y-m-d", DateTimeInterface, or null
|
||||
* @param string $sourceTz Timezone of stored value (DB). Default: UTC
|
||||
* @param string|null $displayTz Target timezone (defaults to user_timezone() or configured school timezone)
|
||||
* @param string|null $defaultTime If $raw is date-only, set this default time ("HH:MM:SS") or null to keep 00:00:00
|
||||
*/
|
||||
function parseDbDateTime($raw, string $sourceTz = 'UTC', ?string $displayTz = null, ?string $defaultTime = null): ?DateTime
|
||||
{
|
||||
if (!$raw) return null;
|
||||
|
||||
// Resolve display timezone dynamically if not provided
|
||||
if ($displayTz === null || $displayTz === '') {
|
||||
try {
|
||||
$displayTz = (string) (config('School')->attendance['timezone'] ?? user_timezone());
|
||||
} catch (Throwable $e) {
|
||||
$displayTz = user_timezone();
|
||||
}
|
||||
}
|
||||
|
||||
if ($raw instanceof DateTimeInterface) {
|
||||
$dt = new DateTime('@' . $raw->getTimestamp());
|
||||
return $dt->setTimezone(new DateTimeZone($displayTz));
|
||||
}
|
||||
|
||||
$s = trim((string)$raw);
|
||||
if ($s === '' || preg_match('/^0{4}-0{2}-0{2}/', $s)) return null;
|
||||
|
||||
$srcTz = new DateTimeZone($sourceTz);
|
||||
$outTz = new DateTimeZone($displayTz);
|
||||
|
||||
// Try full datetime first
|
||||
$dt = DateTime::createFromFormat('Y-m-d H:i:s', $s, $srcTz);
|
||||
if ($dt !== false) {
|
||||
return $dt->setTimezone($outTz);
|
||||
}
|
||||
|
||||
// Try date-only
|
||||
$d = DateTime::createFromFormat('Y-m-d', $s, $srcTz);
|
||||
if ($d !== false) {
|
||||
if ($defaultTime) {
|
||||
[$H, $i, $sec] = array_map('intval', explode(':', $defaultTime));
|
||||
$d->setTime($H, $i, $sec);
|
||||
} // else leave 00:00:00
|
||||
return $d->setTimezone($outTz);
|
||||
}
|
||||
|
||||
// Fallback parser
|
||||
try {
|
||||
$fallback = new DateTime($s, $srcTz);
|
||||
return $fallback->setTimezone($outTz);
|
||||
} catch (Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container my-5">
|
||||
<h3 class="text-center text-success" style="font-family: Arial, sans-serif;">Invoices and Payments</h3>
|
||||
</div>
|
||||
|
||||
<!-- School Year Filter -->
|
||||
<form action="<?= base_url('/parent/invoice_payment') ?>" method="get" class="form-inline mb-3">
|
||||
<div class="d-flex align-items-center justify-content-center">
|
||||
<select name="school_year" id="school_year" class="form-control me-3">
|
||||
<?php foreach ($schoolYears as $year): ?>
|
||||
<option value="<?= esc($year['school_year']) ?>"
|
||||
<?= ($selectedYear === $year['school_year']) ? 'selected' : '' ?>
|
||||
<?= ($currentSchoolYear === $year['school_year']) ? 'data-current="true"' : '' ?>>
|
||||
<?= esc($year['school_year']) ?><?= ($currentSchoolYear === $year['school_year']) ? ' (Current)' : '' ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-success">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Display Payment Notice / Deadline -->
|
||||
<?php
|
||||
$displayTz = user_timezone();
|
||||
$deadline = parseDbDateTime($dueDate, 'UTC', $displayTz); // format either DATE or DATETIME safely
|
||||
?>
|
||||
<div class="alert alert-info mb-3 d-inline-block" style="display: inline-block; width: auto; padding: 10px;">
|
||||
<ul class="mb-0">
|
||||
<li>
|
||||
This website release version does not have an option to pay your invoice online.
|
||||
All payments this school year will be made in person on first day of school
|
||||
(<strong><?= esc($deadline ? $deadline->format('m-d-Y') : 'TBD') ?></strong>).
|
||||
</li>
|
||||
<li>
|
||||
Cash, checks and debit/credit cards are all accepted forms of payment. However, if you elect to pay in
|
||||
installments, only cash and checks will be accepted.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Invoice Table -->
|
||||
<?php if (!empty($invoices)): ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Invoice Number</th>
|
||||
<th>Issue Date</th>
|
||||
<th>Due Date</th>
|
||||
<th>Balance</th>
|
||||
<th>Last Payment Amount</th>
|
||||
<th>Last Payment Date</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($invoices as $index => $invoice): ?>
|
||||
<?php
|
||||
$issueDt = parseDbDateTime($invoice['issue_date'] ?? null, 'UTC', $displayTz); // assume stored UTC
|
||||
$dueDt = parseDbDateTime($invoice['due_date'] ?? null, 'UTC', $displayTz, '12:00:00'); // if date-only, set noon
|
||||
$lastPay = parseDbDateTime($invoice['last_payment_date'] ?? null, 'UTC', $displayTz);
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td><?= (int)$index + 1 ?></td>
|
||||
<td><?= esc($invoice['invoice_number']) ?></td>
|
||||
<td><?= $issueDt ? esc($issueDt->format('m-d-Y h:i A')) : '—' ?></td>
|
||||
<td><?= $dueDt ? esc($dueDt->format('m-d-Y')) : '—' ?></td>
|
||||
<td>$<?= number_format((float)($invoice['balance'] ?? 0), 2) ?></td>
|
||||
<td>$<?= number_format((float)($invoice['last_paid_amount'] ?? 0), 2) ?></td>
|
||||
<td><?= $lastPay ? esc($lastPay->format('m-d-Y h:i A')) : '—' ?></td>
|
||||
<td><?= esc($invoice['status'] ?? '') ?></td>
|
||||
<td>
|
||||
<a href="<?= base_url('invoice/pdf/' . (int)($invoice['id'] ?? 0)) ?>" target="_blank"
|
||||
class="btn btn-info btn-sm external-link">View/Print PDF</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info mb-3 d-inline-block">
|
||||
No invoice found for the selected school year.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const dropdown = document.getElementById('school_year');
|
||||
const options = dropdown.options;
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i].dataset.current === "true") {
|
||||
options[i].style.fontWeight = 'bold';
|
||||
if (!dropdown.value) dropdown.selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function showPaymentDevelopmentMessage(event) {
|
||||
event.preventDefault();
|
||||
alert('The payment method is currently under development. Please contact the school administration at alrahma.isgl@gmail.com');
|
||||
}
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="alert alert-info mb-3 d-inline-block">
|
||||
No students found. Please register your child first. To do so, click the button below.
|
||||
</div>
|
||||
<div class="d-block"> <!-- Force new line -->
|
||||
<a href="<?= site_url('/parent/child_register') ?>" class="btn btn-primary">Register Student</a>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<main class="col-12 px-md-4">
|
||||
<div class="pt-3 pb-2 mb-3 dashboard-title">
|
||||
<h1 class="h2">Messages</h1>
|
||||
<h5 class="h5 mt-2">Send and receive messages from teachers and school administrators.</h5>
|
||||
</div>
|
||||
|
||||
<!-- Section to display received messages -->
|
||||
<div class="mb-4">
|
||||
<h3>Received Messages</h3>
|
||||
<?php if (!empty($receivedMessages)): ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Message Number</th>
|
||||
<th scope="col">From</th>
|
||||
<th scope="col">Subject</th>
|
||||
<th scope="col">Message</th>
|
||||
<th scope="col">Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($receivedMessages as $message): ?>
|
||||
<tr>
|
||||
<td><?= $message['message_number'] ?></td>
|
||||
<td><?= $message['sender_name'] ?></td>
|
||||
<td><?= $message['subject'] ?></td>
|
||||
<td><?= $message['message'] ?></td>
|
||||
<td><?= !empty($message['date_sent']) ? esc(local_datetime($message['date_sent'], 'm-d-Y H:i')) : '' ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p>No messages found.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Section to send new messages -->
|
||||
<div class="mb-4">
|
||||
<h3>Send a Message</h3>
|
||||
<form action="<?= base_url('messages/send') ?>" method="post">
|
||||
<div class="form-group">
|
||||
<label for="recipient">Recipient</label>
|
||||
<select class="form-control" id="recipient" name="recipient" required>
|
||||
<option value="teacher">Teacher</option>
|
||||
<option value="administration">Administration</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject">Subject</label>
|
||||
<input type="text" class="form-control" id="subject" name="subject" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="message">Message</label>
|
||||
<textarea class="form-control" id="message" name="message" rows="4" required></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Send Message</button>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
|
||||
<div class="pt-3 pb-2 mb-3" style="margin-left: -2in;">
|
||||
<h1 class="h2">Payment Success</h1>
|
||||
<h5 class="h5 mt-2">Your tuition fees have been successfully paid.</h5>
|
||||
</div>
|
||||
<!-- Main content -->
|
||||
<div class="alert alert-success" style="margin-left: -2in;">
|
||||
<strong>Success!</strong> Your tuition fees have been successfully paid.
|
||||
</div>
|
||||
<div class="text-center" style="margin-left: -2in;">
|
||||
<a href="<?= base_url('/parent/dashboard') ?>" class="btn btn-primary">Go to Dashboard</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,52 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container mt-5">
|
||||
<h2 class="text-center">Payment Details</h2>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<h4>Payment Plan</h4>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th>Invoice Number</th>
|
||||
<td><?= esc($payment['invoice_number']) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total Amount</th>
|
||||
<td><?= number_format($payment['total_amount'], 2) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Paid Amount</th>
|
||||
<td><?= number_format($payment['paid_amount'], 2) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Balance</th>
|
||||
<td><?= number_format($payment['balance_amount'], 2) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Number of Installments</th>
|
||||
<td><?= esc($payment['number_of_installments']) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Semester</th>
|
||||
<td><?= esc($payment['semester']) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<td><?= esc($payment['status']) ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h4>Payment Options</h4>
|
||||
<form method="post" action="<?= base_url('payments/createPaypalPayment/' . $payment['id']) ?>">
|
||||
<?= csrf_field(); ?>
|
||||
<button type="submit" class="btn btn-primary btn-block">
|
||||
Pay via PayPal
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
$disableStudentBtn = count($existingKids) >= $maxChilds;
|
||||
$disableEmergencyBtn = count($emergencies) >= $maxEmergency;
|
||||
?>
|
||||
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container my-5">
|
||||
<h3 class="text-center text-success mb-3" style="font-family: Arial, sans-serif;">Student Registration</h3>
|
||||
<?php if ($disableStudentBtn): ?>
|
||||
<div class="alert alert-info mt-2">You've reached the maximum number of students (<?= $maxChilds ?>).</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($disableEmergencyBtn): ?>
|
||||
<!--div class="alert alert-info mt-2">You've reached the maximum number of emergency contacts (<--?= $maxEmergency ?>).</div-->
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?= esc(session()->getFlashdata('error')) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (session('errors')): ?>
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<?php foreach (session('errors') as $error): ?>
|
||||
<li><?= esc($error) ?></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// Check if at least one student is not enrolled
|
||||
$hasUnenrolled = false;
|
||||
foreach ($existingKids as $kid) {
|
||||
if ($kid['enrollment'] == 0) {
|
||||
$hasUnenrolled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if ($hasUnenrolled): ?>
|
||||
<div class="p-3 mb-4 border border-danger rounded bg-light text-center">
|
||||
<h5 class="text-danger mb-2">
|
||||
⚠ Please ensure that all of your students are enrolled.
|
||||
</h5>
|
||||
<p class="mb-3">
|
||||
Please complete their enrollment using the button below to ensure they are able to attend classes.
|
||||
</p>
|
||||
<a href="<?= base_url('/parent/enroll_classes') ?>"
|
||||
class="btn btn-lg btn-success bi bi-pencil-square"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom"
|
||||
title="Enroll registered students in their appropriate grade level or course.">
|
||||
Enroll in Classes
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($existingKids)): ?>
|
||||
<h5>Student Information</h5>
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>School ID</th>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>DOB</th>
|
||||
<th>Grade</th>
|
||||
<th>Medical Conditions</th>
|
||||
<th>Allergies</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($existingKids as $kid): ?>
|
||||
<tr>
|
||||
<td><?= esc($kid['school_id']) ?></td>
|
||||
<td><?= esc($kid['firstname']) ?></td>
|
||||
<td><?= esc($kid['lastname']) ?></td>
|
||||
<td><?= esc((new DateTime($kid['dob']))->format('m-d-Y')) ?></td>
|
||||
<td><?= esc($kid['registration_grade']) ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$mc = is_array($kid['medical_conditions'] ?? null)
|
||||
? $kid['medical_conditions']
|
||||
: (strlen($kid['medical_conditions'] ?? '') > 0
|
||||
? array_map('trim', explode(',', $kid['medical_conditions']))
|
||||
: ['N/A']);
|
||||
// Escape each item, then join with real <br> (not escaped)
|
||||
echo implode('<br>', array_map('esc', $mc));
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$al = is_array($kid['allergies'] ?? null)
|
||||
? $kid['allergies']
|
||||
: (strlen($kid['alalergies'] ?? '') > 0
|
||||
? array_map('trim', explode(',', $kid['allergies']))
|
||||
: ['N/A']);
|
||||
echo implode('<br>', array_map('esc', $al));
|
||||
?>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<?php if ($kid['enrollment'] == 0): ?>
|
||||
<form action="<?= base_url('/parent/delete_student/' . $kid['id']) ?>"
|
||||
method="post"
|
||||
style="display:inline">
|
||||
<?= csrf_field() ?>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-danger"
|
||||
aria-label="Delete this student"
|
||||
title="Delete this student"
|
||||
onclick="if (confirm('Are you sure you want to delete this student?')) { this.closest('form').submit(); }">
|
||||
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||
<span class="ms-1">Delete</span>
|
||||
</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" disabled title="Student is already enrolled">
|
||||
<i class="fas fa-ban"></i> Delete
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $student = $kid; ?>
|
||||
<?php include(APPPATH . 'Views/parent/edit_student_modal.php'); ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($emergencies)): ?>
|
||||
<h5 class="mt-4">Emergency Contacts</h5>
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Phone</th>
|
||||
<th>Relation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($emergencies as $contact): ?>
|
||||
<?php
|
||||
$fullName = $contact['emergency_contact_name'] ?? '';
|
||||
$nameParts = explode(' ', trim($fullName), 2);
|
||||
$firstName = $nameParts[0] ?? '';
|
||||
$lastName = $nameParts[1] ?? '';
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc($firstName) ?></td>
|
||||
<td><?= esc($lastName) ?></td>
|
||||
<td><?= esc($contact['cellphone']) ?></td>
|
||||
<td><?= esc($contact['relation']) ?></td>
|
||||
</tr>
|
||||
<?php include(APPPATH . 'Views/parent/edit_emergency_contact.php'); ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
$today = local_date(utc_now(), 'Y-m-d');
|
||||
$disableDueToDate = ($today >= $lastDayOfRegistration);
|
||||
$disableAll = $disableStudentBtn || $disableDueToDate;
|
||||
?>
|
||||
<form action="<?= base_url('/parent/register_student/save') ?>"
|
||||
method="post"
|
||||
id="studentRegistrationForm"
|
||||
data-max-students="<?= $maxChilds ?>"
|
||||
data-existing-students="<?= count($existingKids) ?>"
|
||||
data-max-emergency="<?= $maxEmergency ?>"
|
||||
data-existing-emergencies="<?= count($emergencies) ?>">
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<div id="studentFormsContainer"></div>
|
||||
<div id="emergencyFormsContainer"></div>
|
||||
|
||||
<div class="text-center mb-3" id="initialButtons">
|
||||
<button type="button"
|
||||
class="btn btn-outline-primary me-2 <?= $disableAll ? 'disabled' : '' ?>"
|
||||
id="addStudentBtn"
|
||||
title="<?php
|
||||
if ($disableStudentBtn) {
|
||||
echo "Maximum of $maxChilds students reached.";
|
||||
} elseif ($disableDueToDate) {
|
||||
echo "Registration is closed after $lastDayOfRegistration.";
|
||||
}
|
||||
?>"
|
||||
<?= $disableAll ? 'disabled' : '' ?>>
|
||||
<i class="fas fa-user-plus"></i> Add Student
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-center mb-3 d-none" id="formActionButtons">
|
||||
<button type="button"
|
||||
class="btn btn-outline-primary me-2 <?= $disableAll ? 'disabled' : '' ?>"
|
||||
id="addAnotherStudentBtn"
|
||||
title="<?php
|
||||
if ($disableStudentBtn) {
|
||||
echo "Maximum of $maxChilds students reached.";
|
||||
} elseif ($disableDueToDate) {
|
||||
echo "Registration is closed after $lastDayOfRegistration.";
|
||||
}
|
||||
?>"
|
||||
<?= $disableAll ? 'disabled' : '' ?>>
|
||||
<i class="fas fa-user-plus"></i> Add Another Student
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-outline-primary me-2"
|
||||
id="doneWithStudentBtn">
|
||||
<i class="fas fa-check"></i> Done With Student(s)
|
||||
</button>
|
||||
|
||||
<button type="submit" class="btn btn-success d-none" id="saveFormBtn">
|
||||
<i class="fas fa-save"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Picture Policy Modal -->
|
||||
<div class="modal fade" id="picturePolicyModal" tabindex="-1" aria-labelledby="picturePolicyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title text-success" id="picturePolicyModalLabel">Picture & Media Agreement</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" style="white-space: pre-wrap;">
|
||||
<?php
|
||||
$picturePolicy = include(APPPATH . 'Views/policy/picture_policy_partial.php');
|
||||
$sections = $picturePolicy['sections'] ?? [];
|
||||
$title = $picturePolicy['title'] ?? '';
|
||||
?>
|
||||
<h3 class="text-success"><?= esc($title) ?></h3>
|
||||
<?php if (!empty($sections)): ?>
|
||||
<?php foreach ($sections as $section): ?>
|
||||
<h4 class="mt-4"><?= esc($section['heading']) ?></h4>
|
||||
|
||||
<?php if (isset($section['subsections'][0])): ?>
|
||||
<?php foreach ($section['subsections'] as $sub): ?>
|
||||
<?php if (!empty($sub['title'])): ?>
|
||||
<h5><?= esc($sub['title']) ?></h5>
|
||||
<?php endif; ?>
|
||||
<p><?= nl2br(esc($sub['body'] ?? '')) ?></p>
|
||||
<?php endforeach; ?>
|
||||
<?php elseif (isset($section['subsections']['body'])): ?>
|
||||
<p><?= nl2br(esc($section['subsections']['body'])) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-outline-primary" onclick="window.print()">Print</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hidden Templates -->
|
||||
<div id="studentFormTemplate" class="d-none">
|
||||
<?= view('partials/student_form') ?>
|
||||
</div>
|
||||
|
||||
<div id="emergencyFormTemplate" class="d-none">
|
||||
<?= view('partials/emergencycontact_form') ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$tz = new DateTimeZone((string) (config('School')->attendance['timezone'] ?? user_timezone()));
|
||||
|
||||
$now = new DateTime('now', $tz);
|
||||
$closeAt = new DateTime($lastDayOfRegistration . ' 00:00:00', $tz);
|
||||
|
||||
// Closed at the start of the close date
|
||||
$disableDueToDate = ($now >= $closeAt);
|
||||
|
||||
// Last usable calendar day (date - 1)
|
||||
$lastDayFmt = (clone $closeAt)->modify('-1 day')->format('m-d-Y');
|
||||
|
||||
// Also prepare a precise closing moment string
|
||||
$closeAtFmt24 = $closeAt->format('m-d-Y H:i T'); // e.g., 10-01-2025 00:00 EDT
|
||||
$closeAtFmt12 = $closeAt->format('m-d-Y g:i A T'); // e.g., 10-01-2025 12:00 AM EDT
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<?php if ($disableDueToDate): ?>
|
||||
<!-- Registration Closed Modal -->
|
||||
<div class="modal fade" id="regClosedModal" tabindex="-1" aria-labelledby="regClosedModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-danger">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title text-danger" id="regClosedModalLabel">Registration & Enrollment Closed</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Registration/enrollment is over for this school year.<br>
|
||||
<strong>Last day:</strong> <?= esc($lastDayFmt) ?> (until 11:59 PM)<br>
|
||||
<strong>Closed at:</strong> <?= esc($closeAtFmt24) ?> <!-- or <?= esc($closeAtFmt12) ?> -->
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Optional inline banner as well -->
|
||||
<div class="alert alert-danger d-flex align-items-center my-3" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<div>
|
||||
Registration/enrollment is closed.<br>
|
||||
Last day to register was <strong><?= esc($lastDayFmt) ?></strong> (until <strong>11:59 PM</strong>).<br>
|
||||
It closed at <strong><?= esc($closeAtFmt24) ?></strong> <!-- or <?= esc($closeAtFmt12) ?> -->
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<?php if ($disableDueToDate): ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var modalEl = document.getElementById('regClosedModal');
|
||||
if (modalEl && window.bootstrap) {
|
||||
var m = new bootstrap.Modal(modalEl);
|
||||
m.show();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<script>
|
||||
window.appConfig = {
|
||||
registrationAgeDeadline: "<?= esc($registrationAgeDeadline) ?>"
|
||||
};
|
||||
</script>
|
||||
<!-- Only keep the script imports -->
|
||||
<script type="module" src="/assets/js/name_validation.js"></script>
|
||||
<script type="module" src="/assets/js/age_validation.js"></script>
|
||||
<script type="module" src="/assets/js/phone_validation.js"></script>
|
||||
<script type="module" src="/assets/js/validate_student.js"></script>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,475 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container my-5" style="max-width: 880px;">
|
||||
<h3 class="text-center text-success mb-4" style="font-family: Arial, sans-serif;">
|
||||
Report Absence/Late/Early Dismissal
|
||||
</h3>
|
||||
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="alert alert-danger"><?= esc(session()->getFlashdata('error')) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('message')): ?>
|
||||
<div class="alert alert-success">
|
||||
<?= session()->getFlashdata('message') ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
// Build preview/edit table for upcoming reports
|
||||
$myReports = is_array($myReports ?? null) ? $myReports : [];
|
||||
$tzName = 'UTC';
|
||||
try { $tzName = (string)(config('School')->attendance['timezone'] ?? user_timezone()); } catch (\Throwable $e) { $tzName = user_timezone(); }
|
||||
$nowTz = new DateTime('now', new DateTimeZone($tzName));
|
||||
?>
|
||||
|
||||
<?php if (!empty($myReports)): ?>
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header bg-light"><strong>Upcoming Submissions (Preview & Edit)</strong></div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Student</th>
|
||||
<th>Date</th>
|
||||
<th>Type</th>
|
||||
<th>Time</th>
|
||||
<th>Reason</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($myReports as $r): ?>
|
||||
<?php
|
||||
$reportDate = (string)($r['report_date'] ?? '');
|
||||
$reportDateLabel = $reportDate !== '' ? local_date($reportDate, 'm-d-Y') : '';
|
||||
$type = (string)($r['type'] ?? '');
|
||||
$isLate = ($type === 'late');
|
||||
$isED = ($type === 'early_dismissal');
|
||||
$timeVal = $isLate ? ($r['arrival_time'] ?? '') : ($isED ? ($r['dismiss_time'] ?? '') : '');
|
||||
$status = (string)($r['status'] ?? '');
|
||||
$cutoff = null; $editable = false;
|
||||
try { $cutoff = new DateTime($reportDate . ' 09:00:00', new DateTimeZone($tzName)); } catch (\Throwable $e) { $cutoff = null; }
|
||||
if ($cutoff) {
|
||||
$editable = ($status === 'new') && ($nowTz < $cutoff);
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc(trim(($r['firstname'] ?? '') . ' ' . ($r['lastname'] ?? ''))) ?></td>
|
||||
<td><?= esc($reportDateLabel) ?></td>
|
||||
<td><?= esc(ucwords(str_replace('_', ' ', $type))) ?></td>
|
||||
<td><?= esc($timeVal ?: '—') ?></td>
|
||||
<td><?= esc($r['reason'] ?? '') ?></td>
|
||||
<td><?= esc($status ?: 'new') ?></td>
|
||||
<td>
|
||||
<?php if ($editable): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" data-edit-row="<?= (int)$r['id'] ?>">Edit</button>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">—</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ($editable): ?>
|
||||
<tr class="d-none" data-edit-form-row="<?= (int)$r['id'] ?>">
|
||||
<td colspan="7">
|
||||
<form method="post" action="<?= site_url('parent/report-attendance/update') ?>" class="row g-2 align-items-end">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="id" value="<?= (int)$r['id'] ?>">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Type</label>
|
||||
<input type="text" class="form-control" value="<?= esc(ucwords(str_replace('_', ' ', $type))) ?>" disabled>
|
||||
</div>
|
||||
<?php if ($isLate): ?>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Arrival Time</label>
|
||||
<input type="time" class="form-control" name="arrival_time" value="<?= esc(substr((string)$timeVal,0,5)) ?>">
|
||||
</div>
|
||||
<?php elseif ($isED): ?>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Dismissal Time</label>
|
||||
<input type="time" class="form-control" name="dismiss_time" value="<?= esc(substr((string)$timeVal,0,5)) ?>">
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Time</label>
|
||||
<input type="text" class="form-control" value="—" disabled>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-md-5">
|
||||
<label class="form-label">Reason</label>
|
||||
<input type="text" class="form-control" name="reason" value="<?= esc((string)($r['reason'] ?? '')) ?>" placeholder="Optional">
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button type="submit" class="btn btn-success btn-sm">Save</button>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-cancel-edit="<?= (int)$r['id'] ?>">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="text-muted small">Editing allowed until 9:00 AM on the report date.</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form id="reportForm"
|
||||
method="post"
|
||||
action="<?= site_url('parent/report-attendance') ?>"
|
||||
data-csrf-name="<?= esc(csrf_token()) ?>"
|
||||
data-csrf-value="<?= esc(csrf_hash()) ?>"
|
||||
data-check-url="<?= site_url('api/parent/report-attendance/check') ?>">
|
||||
<input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>">
|
||||
|
||||
<div id="clientCheckAlert" class="alert d-none" role="alert"></div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Select Child(ren)</label>
|
||||
<div class="row g-2">
|
||||
<?php if (!empty($students)): ?>
|
||||
<?php foreach ($students as $s): ?>
|
||||
<div class="col-md-6">
|
||||
<div class="form-check border rounded p-2" data-student-box="<?= (int)$s['id'] ?>">
|
||||
<?php
|
||||
$oldStudents = (array) old('student_ids');
|
||||
$isChecked = in_array((string)$s['id'], array_map('strval', $oldStudents ?? []), true);
|
||||
?>
|
||||
<input class="form-check-input" type="checkbox" name="student_ids[]" id="stu<?= (int)$s['id'] ?>" value="<?= (int)$s['id'] ?>" <?= $isChecked ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="stu<?= (int)$s['id'] ?>">
|
||||
<?= esc($s['firstname'] . ' ' . $s['lastname']) ?>
|
||||
</label>
|
||||
<div class="small mt-1 d-none" data-role="conflict-msg"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning mb-0">No students found under your account.</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-semibold">Sunday Date(s)</label>
|
||||
<select name="dates[]" class="form-select" required multiple size="6" style="max-height: 220px; overflow-y: auto;">
|
||||
<?php
|
||||
$list = $sundays ?? [];
|
||||
$oldDatesRaw = old('dates');
|
||||
$selectedDates = [];
|
||||
if (is_array($oldDatesRaw)) {
|
||||
$selectedDates = array_map('strval', $oldDatesRaw);
|
||||
} elseif ($oldDatesRaw !== null) {
|
||||
$selectedDates = [(string) $oldDatesRaw];
|
||||
} elseif (old('date')) {
|
||||
$selectedDates = [(string) old('date')];
|
||||
} elseif (!empty($defaultDate)) {
|
||||
$selectedDates = [(string) $defaultDate];
|
||||
}
|
||||
$selectedDates = array_unique(array_filter($selectedDates));
|
||||
foreach ($list as $opt):
|
||||
$v = $opt['value'] ?? '';
|
||||
$label = $opt['label'] ?? $v;
|
||||
$isSel = in_array((string)$v, $selectedDates, true);
|
||||
?>
|
||||
<option value="<?= esc($v) ?>" <?= $isSel ? 'selected' : '' ?>><?= esc($label) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<div class="form-text">Select one or more Sundays (hold Ctrl/Cmd or Shift to pick multiple). Scroll for future dates through early June.</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-semibold">Type</label>
|
||||
<select name="type" id="reportType" class="form-select" required>
|
||||
<?php $oldType = (string) (old('type') ?: 'absent'); ?>
|
||||
<option value="absent" <?= $oldType === 'absent' ? 'selected' : '' ?>>Absent</option>
|
||||
<option value="late" <?= $oldType === 'late' ? 'selected' : '' ?>>Late</option>
|
||||
<option value="early_dismissal" <?= $oldType === 'early_dismissal' ? 'selected' : '' ?>>Early Dismissal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3" id="arrivalTimeWrap" style="display:none;">
|
||||
<label class="form-label fw-semibold">Expected Arrival Time</label>
|
||||
<input type="time" name="arrival_time" class="form-control" placeholder="HH:MM" value="<?= esc(old('arrival_time') ?: '') ?>">
|
||||
</div>
|
||||
<div class="col-md-3" id="dismissTimeWrap" style="display:none;">
|
||||
<label class="form-label fw-semibold">Dismissal Time</label>
|
||||
<input type="time" name="dismiss_time" class="form-control" placeholder="HH:MM" value="<?= esc(old('dismiss_time') ?: '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold" id="reasonLabel">Reason</label>
|
||||
<textarea name="reason" id="reasonInput" rows="3" class="form-control" placeholder="Brief reason to help teachers plan."><?= esc(old('reason') ?: '') ?></textarea>
|
||||
<div class="form-text" id="reasonHelp">Required for Absence/Late so we can support your child.</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
<?php $prev = previous_url() ?: site_url('/parent/attendance'); ?>
|
||||
<a href="<?= esc($prev) ?>" class="btn btn-outline-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const typeSel = document.getElementById('reportType');
|
||||
const arrivalWrap = document.getElementById('arrivalTimeWrap');
|
||||
const dismissWrap = document.getElementById('dismissTimeWrap');
|
||||
const reasonField = document.getElementById('reasonInput');
|
||||
const reasonHelp = document.getElementById('reasonHelp');
|
||||
const reasonLabel = document.getElementById('reasonLabel');
|
||||
|
||||
function updateFields() {
|
||||
const v = (typeSel.value || '').toLowerCase();
|
||||
arrivalWrap.style.display = (v === 'late') ? '' : 'none';
|
||||
dismissWrap.style.display = (v === 'early_dismissal') ? '' : 'none';
|
||||
const reasonRequired = (v === 'absent' || v === 'late');
|
||||
if (reasonField) {
|
||||
reasonField.required = reasonRequired;
|
||||
}
|
||||
if (reasonLabel) {
|
||||
reasonLabel.innerHTML = reasonRequired
|
||||
? 'Reason <span class="text-danger">*</span>'
|
||||
: 'Reason (optional)';
|
||||
}
|
||||
if (reasonHelp) {
|
||||
reasonHelp.textContent = reasonRequired
|
||||
? 'Required for absence/late so teachers can plan.'
|
||||
: 'Optional for early dismissal.';
|
||||
}
|
||||
// Nudge visibility into view so parents notice the time field
|
||||
if (v === 'late') {
|
||||
try { arrivalWrap.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } catch(e) {}
|
||||
} else if (v === 'early_dismissal') {
|
||||
try { dismissWrap.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } catch(e) {}
|
||||
}
|
||||
}
|
||||
typeSel.addEventListener('change', updateFields);
|
||||
updateFields();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Inline edit toggling for the preview table
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('[data-edit-row]').forEach(function(btn){
|
||||
btn.addEventListener('click', function(){
|
||||
const id = this.getAttribute('data-edit-row');
|
||||
const row = document.querySelector('[data-edit-form-row="' + id + '"]');
|
||||
if (!row) return;
|
||||
row.classList.toggle('d-none');
|
||||
try { row.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } catch(_) {}
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('[data-cancel-edit]').forEach(function(btn){
|
||||
btn.addEventListener('click', function(){
|
||||
const id = this.getAttribute('data-cancel-edit');
|
||||
const row = document.querySelector('[data-edit-form-row="' + id + '"]');
|
||||
if (!row) return;
|
||||
row.classList.add('d-none');
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Conflict check with CSRF refresh
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('reportForm');
|
||||
if (!form) return;
|
||||
|
||||
let checkUrl = form.getAttribute('data-check-url') || '';
|
||||
let csrfName = form.getAttribute('data-csrf-name') || '';
|
||||
let csrfVal = form.getAttribute('data-csrf-value') || '';
|
||||
const typeSel = document.getElementById('reportType');
|
||||
const dateSel = form.querySelector('select[name="dates[]"]');
|
||||
const submitBtn = form.querySelector('button[type="submit"]');
|
||||
const alertBox = document.getElementById('clientCheckAlert');
|
||||
|
||||
function selectedIds() {
|
||||
const ids = [];
|
||||
form.querySelectorAll('input[name="student_ids[]"]:checked').forEach(cb => {
|
||||
const v = parseInt(cb.value, 10);
|
||||
if (v > 0) ids.push(v);
|
||||
});
|
||||
return ids;
|
||||
}
|
||||
|
||||
function setAlert(kind, html) {
|
||||
if (!alertBox) return;
|
||||
if (!html) {
|
||||
alertBox.className = 'alert d-none';
|
||||
alertBox.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
let cls = 'alert-info';
|
||||
if (kind === 'error') cls = 'alert-danger';
|
||||
else if (kind === 'warn') cls = 'alert-warning';
|
||||
else if (kind === 'ok') cls = 'alert-success';
|
||||
alertBox.className = 'alert ' + cls;
|
||||
alertBox.innerHTML = html;
|
||||
}
|
||||
|
||||
function setStudentMsg(studentId, msg, kind) {
|
||||
const box = form.querySelector('[data-student-box="' + studentId + '"] [data-role="conflict-msg"]');
|
||||
if (!box) return;
|
||||
if (!msg) {
|
||||
box.classList.add('d-none');
|
||||
box.textContent = '';
|
||||
return;
|
||||
}
|
||||
box.classList.remove('d-none');
|
||||
box.classList.remove('text-danger', 'text-info');
|
||||
box.classList.add(kind === 'info' ? 'text-info' : 'text-danger');
|
||||
box.textContent = msg;
|
||||
}
|
||||
|
||||
function selectedDates() {
|
||||
if (!dateSel) return [];
|
||||
return Array.from(dateSel.selectedOptions || [])
|
||||
.map(opt => opt.value)
|
||||
.filter(v => v);
|
||||
}
|
||||
|
||||
async function runCheck() {
|
||||
setAlert('', '');
|
||||
const ids = selectedIds();
|
||||
const dates = selectedDates();
|
||||
if (!checkUrl || !dateSel || !typeSel) return;
|
||||
if (!ids.length || !dates.length) {
|
||||
if (submitBtn) submitBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
form.querySelectorAll('[data-student-box] input[type="checkbox"]').forEach(cb => {
|
||||
cb.disabled = false;
|
||||
});
|
||||
form.querySelectorAll('[data-role="conflict-msg"]').forEach(el => {
|
||||
el.classList.add('d-none');
|
||||
el.textContent = '';
|
||||
});
|
||||
|
||||
const body = new URLSearchParams();
|
||||
body.append(csrfName, csrfVal);
|
||||
dates.forEach(function(d) {
|
||||
body.append('dates[]', d);
|
||||
});
|
||||
body.append('type', typeSel.value || '');
|
||||
ids.forEach(id => body.append('student_ids[]', String(id)));
|
||||
|
||||
try {
|
||||
const res = await fetch(checkUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
[csrfName]: csrfVal
|
||||
},
|
||||
body: body.toString()
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// ✅ Refresh CSRF token if returned
|
||||
if (data?.csrf) {
|
||||
csrfName = data.csrf.name;
|
||||
csrfVal = data.csrf.hash;
|
||||
form.setAttribute('data-csrf-name', csrfName);
|
||||
form.setAttribute('data-csrf-value', csrfVal);
|
||||
const hidden = form.querySelector('input[name="' + csrfName + '"]');
|
||||
if (hidden) hidden.value = csrfVal;
|
||||
}
|
||||
|
||||
if (!data || !data.ok) {
|
||||
if (submitBtn) submitBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const byId = {};
|
||||
(data.students || []).forEach(s => {
|
||||
byId[s.student_id] = s;
|
||||
});
|
||||
|
||||
const type = (typeSel.value || '').toLowerCase();
|
||||
const conflicts = [];
|
||||
const infoOnly = [];
|
||||
|
||||
ids.forEach(id => {
|
||||
const s = byId[id];
|
||||
const dateTypes = (s && s.dates) ? s.dates : {};
|
||||
const fullname = (s ? ((s.firstname || '') + ' ' + (s.lastname || '')) : ('Student #' + id)).trim();
|
||||
const conflictDates = [];
|
||||
const infoDates = [];
|
||||
|
||||
dates.forEach(function(dateVal) {
|
||||
const entry = dateTypes && dateTypes[dateVal];
|
||||
const typesForDate = Array.isArray(entry) ? entry : [];
|
||||
if (!typesForDate.length) return;
|
||||
if (type === 'early_dismissal') {
|
||||
if (typesForDate.includes('absent') || typesForDate.includes('late')) {
|
||||
conflictDates.push(dateVal);
|
||||
} else if (typesForDate.includes('early_dismissal')) {
|
||||
infoDates.push(dateVal);
|
||||
}
|
||||
} else {
|
||||
conflictDates.push(dateVal);
|
||||
}
|
||||
});
|
||||
|
||||
if (conflictDates.length) {
|
||||
conflicts.push(fullname + ' (' + conflictDates.join(', ') + ')');
|
||||
setStudentMsg(id, 'Already submitted for: ' + conflictDates.join(', '), 'error');
|
||||
const cb = form.querySelector('[data-student-box="' + id + '"] input[type="checkbox"]');
|
||||
if (cb) {
|
||||
cb.checked = false;
|
||||
cb.disabled = true;
|
||||
}
|
||||
} else if (infoDates.length) {
|
||||
infoOnly.push(fullname + ' (' + infoDates.join(', ') + ')');
|
||||
setStudentMsg(id, 'Early dismissal already submitted for: ' + infoDates.join(', ') + ' — time will be updated.', 'info');
|
||||
}
|
||||
});
|
||||
|
||||
if (conflicts.length && ids.length === conflicts.length) {
|
||||
setAlert('warn', 'All selected students have existing submissions for the chosen date(s).');
|
||||
} else if (conflicts.length) {
|
||||
setAlert('warn', 'Some selections disabled due to existing submissions on selected dates.');
|
||||
} else if (infoOnly.length) {
|
||||
setAlert('info', 'Note: some students already have early dismissal on these dates—time will be updated.');
|
||||
} else {
|
||||
setAlert('', '');
|
||||
}
|
||||
|
||||
if (submitBtn) submitBtn.disabled = (selectedIds().length === 0);
|
||||
} catch (e) {
|
||||
setAlert('warn', 'Could not verify submissions right now. You may proceed; server will validate.');
|
||||
if (submitBtn) submitBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
form.addEventListener('change', function(e) {
|
||||
const tgt = e.target;
|
||||
if (!tgt) return;
|
||||
if (tgt.matches('select[name="dates[]"], #reportType, input[name="student_ids[]"]')) {
|
||||
runCheck();
|
||||
}
|
||||
});
|
||||
|
||||
runCheck();
|
||||
});
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,121 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container my-5">
|
||||
<h3 class="text-center text-success" style="font-family: Arial, sans-serif;">Scores</h2>
|
||||
</div>
|
||||
|
||||
<!-- Filter Form -->
|
||||
<form action="" method="get" class="form-inline">
|
||||
<div class="d-flex align-items-center">
|
||||
<select name="school_year" id="school_year" class="form-control me-3"> <!-- Added me-3 (right margin) -->
|
||||
<?php foreach ($schoolYears as $year): ?>
|
||||
<option value="<?= esc($year) ?>" <?= $selectedYear === $year ? 'selected' : '' ?>>
|
||||
<?= esc($year) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-success">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<!-- Scores Table -->
|
||||
<?php $yearScores = $organizedScores[$selectedYear] ?? []; ?>
|
||||
<?php $semesterOrder = $semesterOrder ?? ['Fall', 'Spring']; ?>
|
||||
<?php
|
||||
$showExamScores = $showExamScores ?? true;
|
||||
$showExamScoresBySemester = $showExamScoresBySemester ?? [];
|
||||
?>
|
||||
|
||||
<?php if (empty($yearScores)): ?>
|
||||
<div class="alert alert-info mb-3 d-inline-block">No scores available for the selected year.</div>
|
||||
<?php else: ?>
|
||||
<div class="accordion mt-4" id="parentScoresAccordion">
|
||||
<?php foreach ($semesterOrder as $index => $semester): ?>
|
||||
<?php
|
||||
$semesterScores = $yearScores[$semester] ?? [];
|
||||
$showExamScoresForSemester = $showExamScoresBySemester[$semester] ?? $showExamScores;
|
||||
$columnCount = $showExamScoresForSemester ? 11 : 8;
|
||||
$headingId = 'heading' . strtolower($semester);
|
||||
$collapseId = 'collapse' . strtolower($semester);
|
||||
$isActive = $index === 0;
|
||||
?>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="<?= esc($headingId) ?>">
|
||||
<button class="accordion-button <?= $isActive ? '' : 'collapsed' ?>" type="button"
|
||||
data-bs-toggle="collapse" data-bs-target="#<?= esc($collapseId) ?>"
|
||||
aria-expanded="<?= $isActive ? 'true' : 'false' ?>" aria-controls="<?= esc($collapseId) ?>">
|
||||
<?= esc($semester) ?> Semester
|
||||
</button>
|
||||
</h2>
|
||||
<div id="<?= esc($collapseId) ?>" class="accordion-collapse collapse <?= $isActive ? 'show' : '' ?>"
|
||||
aria-labelledby="<?= esc($headingId) ?>" data-bs-parent="#parentScoresAccordion">
|
||||
<div class="accordion-body p-0">
|
||||
<?php if (!empty($semesterScores)): ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>School ID</th>
|
||||
<th>Student Name</th>
|
||||
<th>Class Section</th>
|
||||
<th>Homework</th>
|
||||
<th>Project</th>
|
||||
<th>Participation</th>
|
||||
<th>Quiz</th>
|
||||
<th>Attendance</th>
|
||||
<?php if ($showExamScoresForSemester): ?><th>PTAP</th><?php endif; ?>
|
||||
<?php if ($semester === 'Fall'): ?>
|
||||
<?php if ($showExamScoresForSemester): ?><th>Midterm</th><?php endif; ?>
|
||||
<?php elseif ($semester === 'Spring'): ?>
|
||||
<?php if ($showExamScoresForSemester): ?><th>Final Exam</th><?php endif; ?>
|
||||
<?php else: ?>
|
||||
<?php if ($showExamScoresForSemester): ?><th>Exam</th><?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php if ($showExamScoresForSemester): ?><th>Semester Score</th><?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($semesterScores as $student): ?>
|
||||
<tr>
|
||||
<td><?= esc($student['school_id']) ?></td>
|
||||
<td><?= esc($student['student_firstname'] . ' ' . $student['student_lastname']) ?></td>
|
||||
<td><?= esc($student['class_section_name']) ?></td>
|
||||
<td><?= esc($student['scores']['homework']['score'] ?? '-') ?></td>
|
||||
<td><?= esc($student['scores']['project']['score'] ?? '-') ?></td>
|
||||
<td><?= esc($student['scores']['participation_score']['score'] ?? '-') ?></td>
|
||||
<td><?= esc($student['scores']['quiz']['score'] ?? '-') ?></td>
|
||||
<td><?= esc($student['scores']['attendance']['score'] ?? '-') ?></td>
|
||||
<?php if ($showExamScoresForSemester): ?><td><?= esc($student['scores']['ptap']['score'] ?? '-') ?></td><?php endif; ?>
|
||||
|
||||
<?php if ($semester === 'Fall'): ?>
|
||||
<?php if ($showExamScoresForSemester): ?><td><?= esc($student['scores']['midterm_exam']['score'] ?? '-') ?></td><?php endif; ?>
|
||||
<?php elseif ($semester === 'Spring'): ?>
|
||||
<?php if ($showExamScoresForSemester): ?><td><?= esc($student['scores']['final_exam']['score'] ?? '-') ?></td><?php endif; ?>
|
||||
<?php else: ?>
|
||||
<?php if ($showExamScoresForSemester): ?><td><?= esc($student['scores']['midterm_exam']['score'] ?? $student['scores']['final_exam']['score'] ?? '-') ?></td><?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php if ($showExamScoresForSemester): ?><td><?= esc($student['scores']['semester']['score'] ?? '-') ?></td><?php endif; ?>
|
||||
</tr>
|
||||
<?php if (!empty($student['comment'])): ?>
|
||||
<tr>
|
||||
<td colspan="<?= esc($columnCount) ?>"><strong>Teacher Comment:</strong> <?= esc($student['comment']) ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-secondary mb-0">No <?= esc($semester) ?> semester scores recorded yet.</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="message">
|
||||
<img src="<?= base_url('public/images/registration-1.png') ?>" alt="Registration Success">
|
||||
<h1>Your kid(s) has been Successfully registered!</h1>
|
||||
<p>You will be redirected to the home page shortly.</p>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
setTimeout(function() {
|
||||
window.location.href = "<?= base_url('/parent_dashboard') ?>";
|
||||
}, 5000);
|
||||
});
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?= $this->extend('layout/main_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
|
||||
<div class="alert alert-success mt-4">
|
||||
<h4 class="alert-heading">Success!</h4>
|
||||
<p>Students have been successfully withdrawn from the selected classes.</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
Reference in New Issue
Block a user