Files
2026-05-16 13:44:12 -04:00

332 lines
16 KiB
PHP
Executable File

<?= $this->extend('layout/main_layout') ?>
<?= $this->section('content') ?>
<div class="container-xxl py-5">
<div class="container">
<div class="text-center mx-auto mb-5" style="max-width:600px;">
<h4 class="text-dark" style="font-family:Arial,sans-serif;">Class Attendance</h4>
</div>
<?php
$canEdit = isset($canEdit) ? (bool)$canEdit : false;
$sundayDates = isset($sunday_dates) && is_array($sunday_dates) ? array_values($sunday_dates) : [];
$currentSunday = isset($current_sunday) ? (string)$current_sunday : '';
if ($currentSunday === '' && count($sundayDates) > 0) {
$currentSunday = $sundayDates[count($sundayDates) - 1];
}
$historyDates = array_slice($sundayDates, 0, max(0, count($sundayDates) - 1));
$historyDates = array_pad($historyDates, 2, '');
$no_school_days = isset($no_school_days) && is_array($no_school_days) ? $no_school_days : [];
$isNoSchoolToday = $currentSunday !== '' && !empty($no_school_days[$currentSunday]);
$canEditToday = $canEdit && !$isNoSchoolToday;
$btnDisabledAttr = $canEditToday ? '' : ' disabled="disabled"';
$lockedByStudent = isset($locked_by_student) && is_array($locked_by_student) ? $locked_by_student : [];
// Derive a header label showing the actual recent dates (instead of generic text)
$formatDateLabel = function ($value) {
if (!$value) return '—';
$value = (string)$value;
if (preg_match('/^(\\d{4})-(\\d{2})-(\\d{2})/', $value, $m)) {
return $m[2] . '-' . $m[3] . '-' . $m[1];
}
try {
return local_date($value, 'm-d-Y');
} catch (Throwable $e) {
return $value;
}
};
$recentHeaderLabel = $currentSunday ? $formatDateLabel($currentSunday) : 'Last Sunday';
// Teacher columns follow the computed Sunday dates (oldest → newest)
$teacherDateColumns = $sundayDates;
// unified badge rendering
function renderStatusBadge($status)
{
$status = strtolower(trim((string)$status));
if ($status === 'present') return '<span class="badge bg-success">Present</span>';
if ($status === 'late') return '<span class="badge bg-warning text-dark">Late</span>';
if ($status === 'absent') return '<span class="badge bg-danger">Absent</span>';
if ($status === 'no school') return '<span class="badge bg-info text-dark">No&nbsp;School</span>';
return '';
}
// blue tint for entire column
$noSchoolClass = fn($date) => $date && !empty($no_school_days[$date]) ? ' style="background-color:#cff4fc;"' : '';
?>
<?php if ($isNoSchoolToday): ?>
<div class="alert alert-info text-center fw-bold" role="alert">
Today is marked as <strong>No School</strong>. Attendance inputs are disabled.
</div>
<?php endif; ?>
<form action="<?= site_url('/teacher/update_attendance') ?>" method="post" id="attendanceForm">
<?= csrf_field() ?>
<input type="hidden" name="class_section_id" value="<?= esc($class_section_id) ?>">
<input type="hidden" name="class_id" value="<?= esc($class_id ?? '') ?>">
<!-- 🔹 TEACHER ATTENDANCE -->
<div class="card mb-4 shadow-sm">
<div class="card-header bg-light"><strong>Teacher Attendance</strong></div>
<div class="card-body p-0">
<div class="table-responsive">
<table id="teachersTable" class="table table-bordered table-striped m-0 align-middle">
<thead class="table-light">
<tr>
<th class="text-center" style="width:56px;">#</th>
<th>Name</th>
<th class="text-center" style="width:120px;">Role</th>
<?php foreach ($teacherDateColumns as $d): ?>
<th class="text-center" style="width:130px;"><?= esc($formatDateLabel($d)) ?></th>
<?php endforeach; ?>
<th class="text-center" style="width:160px;">Today</th>
<th style="width:240px;">Reason</th>
</tr>
</thead>
<tbody>
<?php if (!empty($teachers)): ?>
<?php $i=1; foreach($teachers as $t): $todayVal=strtolower($t['today']??''); ?>
<tr>
<td class="text-center"><?= $i++ ?></td>
<td><?= esc($t['name']); ?></td>
<td class="text-center"><?= esc($t['position']==='main'?'Main Teacher':'Teacher Assistant'); ?></td>
<!-- Past Sundays (aligned to computed dates) -->
<?php foreach ($teacherDateColumns as $d): ?>
<td class="text-center"<?= $noSchoolClass($d) ?>>
<?php if ($d && !empty($no_school_days[$d])): ?>
<?= renderStatusBadge('no school') ?>
<?php else: ?>
<div class="d-flex flex-column align-items-center">
<?= renderStatusBadge($t['sunday_statuses'][$d] ?? '') ?>
</div>
<?php endif; ?>
</td>
<?php endforeach; ?>
<!-- Today -->
<td class="text-center"<?= $noSchoolClass($currentSunday) ?>>
<?php if ($isNoSchoolToday): ?>
<?= renderStatusBadge('no school') ?>
<?php else: ?>
<input type="hidden" name="teachers[<?= (int)$t['teacher_id'] ?>][teacher_id]" value="<?= (int)$t['teacher_id'] ?>">
<input type="hidden" name="teachers[<?= (int)$t['teacher_id'] ?>][position]" value="<?= esc($t['position']) ?>">
<select name="teachers[<?= (int)$t['teacher_id'] ?>][status]"
<?= $canEditToday?'':'disabled' ?> data-required="1" <?= $canEditToday?'required':'' ?>
style="font-size:.9rem; padding:2px 4px; width:120px;">
<option value="" disabled <?= empty($t['today'])?'selected':'' ?>>Select</option>
<option value="Present" <?= $todayVal==='present'?'selected':'' ?>>Present</option>
<option value="Absent" <?= $todayVal==='absent'?'selected':'' ?>>Absent</option>
<option value="Late" <?= $todayVal==='late'?'selected':'' ?>>Late</option>
</select>
<?php endif; ?>
</td>
<td>
<input type="text"
name="teachers[<?= (int)$t['teacher_id'] ?>][reason]"
placeholder="<?= $isNoSchoolToday?'No School':'Reason (if absent/late)' ?>"
<?= $canEditToday?'':'disabled' ?>
style="font-size:.9rem; padding:4px 6px; width:100%;">
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="8" class="text-center">No teachers assigned.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- 🔹 STUDENT ATTENDANCE -->
<div class="card mb-4 shadow-sm">
<div class="card-header bg-light"><strong>Students Attendance</strong></div>
<div class="card-body p-0">
<div class="table-responsive">
<table id="studentsTable" class="table table-bordered table-striped m-0 align-middle">
<thead class="table-light">
<tr>
<th class="text-center">#</th>
<th style="min-width:160px;">School ID</th>
<th>First Name</th>
<th>Last Name</th>
<?php foreach ($historyDates as $d): ?>
<th class="text-center"><?= esc($formatDateLabel($d)) ?></th>
<?php endforeach; ?>
<th class="text-center"><?= esc($recentHeaderLabel) ?></th>
<th class="text-center">Today</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<?php if (!empty($students)): ?>
<?php $n=1; foreach($students as $a): ?>
<?php
$studentId = (int)($a['student']['id'] ?? 0);
$lockInfo = $lockedByStudent[$studentId] ?? ['locked'=>false,'source'=>null,'reason'=>null,'status'=>$a['today'] ?? null];
$isLocked = !empty($lockInfo['locked']);
$lockSource = $lockInfo['source'] ?? '';
$lockLabel = $lockSource === 'parent' ? 'Parent submitted' : ($lockSource === 'admin' ? 'Admin submitted' : 'Locked');
$todayStatus = $lockInfo['status'] ?? ($a['today'] ?? null);
?>
<tr>
<input type="hidden" name="attendance[<?= (int)$a['student']['id'] ?>][school_id]" value="<?= esc($a['student']['school_id']) ?>">
<input type="hidden" name="attendance[<?= (int)$a['student']['id'] ?>][student_id]" value="<?= (int)$a['student']['id'] ?>">
<td class="text-center"><?= $n++ ?></td>
<td style="min-width:160px;"><?= esc($a['student']['school_id']); ?></td>
<td><?= esc($a['student']['firstname']); ?></td>
<td><?= esc($a['student']['lastname']); ?></td>
<?php foreach ($historyDates as $d): ?>
<td class="text-center"<?= $noSchoolClass($d) ?>>
<?php if (!empty($no_school_days[$d])): ?>
<?= renderStatusBadge('no school') ?>
<?php else: ?>
<?= renderStatusBadge($a['sunday_statuses'][$d] ?? '') ?>
<?php endif; ?>
</td>
<?php endforeach; ?>
<td class="text-center">
<?php
$currentStatus = $a['sunday_statuses'][$currentSunday] ?? '';
$normalizedStatus = strtolower(trim((string)$currentStatus));
?>
<?php if ($normalizedStatus === '' || $normalizedStatus === 'n/a'): ?>
<span class="text-muted small">No data</span>
<?php else: ?>
<div class="d-flex flex-column gap-1 align-items-start align-items-md-center">
<span class="d-flex gap-2 align-items-center">
<?= renderStatusBadge($currentStatus) ?>
</span>
</div>
<?php endif; ?>
</td>
<td class="text-center"<?= $noSchoolClass($currentSunday) ?>>
<?php if ($isNoSchoolToday): ?>
<?= renderStatusBadge('no school') ?>
<?php elseif ($isLocked): ?>
<input type="hidden" name="attendance[<?= (int)$a['student']['id'] ?>][status]" value="<?= esc(ucfirst(strtolower((string)$todayStatus))) ?>">
<div class="d-flex flex-column align-items-center gap-1">
<?= renderStatusBadge($todayStatus ?? '') ?>
<span class="badge bg-secondary" title="This attendance was submitted externally and cannot be edited.">
<?= esc($lockLabel) ?>
</span>
</div>
<?php else: ?>
<select name="attendance[<?= (int)$a['student']['id'] ?>][status]"
<?= $canEditToday?'':'disabled' ?> data-required="1" <?= $canEditToday?'required':'' ?>
style="font-size:.875rem; padding:2px 4px; width:110px;">
<option value="" disabled <?= empty($a['today'])?'selected':'' ?>>Select</option>
<option value="Present" <?= (strtolower($a['today']??'')==='present')?'selected':'' ?>>Present</option>
<option value="Absent" <?= (strtolower($a['today']??'')==='absent')?'selected':'' ?>>Absent</option>
<option value="Late" <?= (strtolower($a['today']??'')==='late')?'selected':'' ?>>Late</option>
</select>
<?php endif; ?>
</td>
<td>
<?php if ($isLocked): ?>
<input type="hidden" name="attendance[<?= (int)$a['student']['id'] ?>][reason]" value="<?= esc($lockInfo['reason'] ?? '') ?>">
<div class="text-muted small">
<?= esc($lockInfo['reason'] ?? 'Submitted externally.') ?>
</div>
<?php else: ?>
<input type="text"
name="attendance[<?= (int)$a['student']['id'] ?>][reason]"
placeholder="<?= $isNoSchoolToday?'No School':'Reason if absent/late' ?>"
<?= $canEditToday?'':'disabled' ?>
style="font-size:.875rem; padding:4px 6px; width:100%;">
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="8" class="text-center">No students found</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="d-flex justify-content-center mt-4 mb-4">
<button type="submit" class="btn btn-success btn-lg px-5 shadow" id="submitAttendanceBtn" <?= $btnDisabledAttr ?>>
Submit Attendance
</button>
</div>
</form>
</div>
</div>
<!-- Confirmation Modal -->
<div class="modal fade" id="confirmSubmitModal" tabindex="-1" aria-labelledby="confirmSubmitLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-info text-dark">
<h5 class="modal-title" id="confirmSubmitLabel">Confirm Submission</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
Are you sure you want to submit?<br><strong>Once submitted you cannot make changes.</strong>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" id="cancelSubmitBtn" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-success" id="confirmSubmitBtn">Yes, Submit</button>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('scripts') ?>
<script>
document.addEventListener("DOMContentLoaded",()=>{
const form=document.getElementById("attendanceForm");
const submitBtn=document.getElementById("submitAttendanceBtn");
const modal=new bootstrap.Modal(document.getElementById("confirmSubmitModal"));
const confirmBtn=document.getElementById("confirmSubmitBtn");
const cancelBtn=document.getElementById("cancelSubmitBtn");
const isNoSchoolToday=<?= $isNoSchoolToday?'true':'false' ?>;
function allRequiredFilled(){
const selects=form.querySelectorAll('select[data-required="1"]:not([disabled])');
for(const s of selects){if(!s.value){s.classList.add('is-invalid');s.focus();return false;}s.classList.remove('is-invalid');}
return true;
}
form.addEventListener("submit",e=>{
e.preventDefault();
if(isNoSchoolToday){alert("Today is marked as No School. Attendance submission is disabled.");return;}
if(!allRequiredFilled()){alert("Please fill all required fields.");return;}
setTimeout(()=>cancelBtn.focus(),150);
modal.show();
});
confirmBtn.addEventListener("click",()=>{
confirmBtn.disabled=true;
submitBtn.disabled=true;
modal.hide();
form.submit();
});
});
</script>
<script>
$(function(){
$('#teachersTable').DataTable({
pageLength:100,
order:[],
columnDefs:[{targets:[0,3,4,5,6],className:'text-center'}]
});
$('#studentsTable').DataTable({
pageLength:100,
order:[],
columnDefs:[{targets:[0,4,5,6,7],className:'text-center'}]
});
});
</script>
<?= $this->endSection() ?>