recreate project

This commit is contained in:
root
2026-02-10 22:11:06 -05:00
commit 663c0cdbda
10149 changed files with 1379710 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
<?php
// Reusable academic filter: School Year + Semester (GET form)
// Usage: include this view in management pages that need academic scoping.
// - Accepts ambient vars if available: $schoolYears, $schoolYear, $semester.
// - Defaults to current config values when not provided via GET or vars.
// - No action attribute to auto-submit to current URL.
// - Reset link uses '?' to clear query string reliably.
// Ensure helper functions are available
if (function_exists('helper')) { @helper('GlobalConfigHelper'); }
// Resolve defaults
$currentYear = function_exists('getSchoolYear') ? (string) (getSchoolYear() ?? '') : '';
$currentSem = function_exists('getSemester') ? (string) (getSemester() ?? '') : '';
if ($currentYear === '' || $currentSem === '') {
try {
$cfg = new \App\Models\ConfigurationModel();
if ($currentYear === '') $currentYear = (string) ($cfg->getConfig('school_year') ?? '');
if ($currentSem === '') $currentSem = (string) ($cfg->getConfig('semester') ?? '');
} catch (\Throwable $e) { /* ignore */ }
}
$selectedYear = (string)($schoolYear ?? ($_GET['school_year'] ?? ''));
if ($selectedYear === '') { $selectedYear = $currentYear; }
$semVal = (string)($semester ?? ($_GET['semester'] ?? ''));
if ($semVal === '') { $semVal = $currentSem; }
$classSectionVal = (string)($classSectionId ?? ($_GET['class_section_id'] ?? ''));
?>
<form method="get" class="row g-2 align-items-center justify-content-center mb-3">
<?php if ($classSectionVal !== ''): ?>
<input type="hidden" name="class_section_id" value="<?= esc($classSectionVal) ?>">
<?php endif; ?>
<div class="col-auto"><label class="form-label mb-0">School year</label></div>
<div class="col-auto">
<?php $years = isset($schoolYears) && is_array($schoolYears) ? $schoolYears : []; ?>
<select name="school_year" class="form-select form-select-sm" style="min-width: 180px;">
<?php if (!empty($years)): ?>
<?php foreach ($years as $y): $val = is_array($y) && isset($y['school_year']) ? (string)$y['school_year'] : (string)$y; ?>
<option value="<?= esc($val) ?>" <?= ($selectedYear === $val ? 'selected' : '') ?>><?= esc($val) ?></option>
<?php endforeach; ?>
<?php else: ?>
<?php if ($selectedYear !== ''): ?>
<option value="<?= esc($selectedYear) ?>" selected><?= esc($selectedYear) ?></option>
<?php else: ?>
<option value="">—</option>
<?php endif; ?>
<?php endif; ?>
</select>
</div>
<div class="col-auto"><label class="form-label mb-0">Semester</label></div>
<div class="col-auto">
<select name="semester" class="form-select form-select-sm" style="min-width: 140px;">
<option value="">—</option>
<option value="Fall" <?= (strcasecmp($semVal, 'Fall') === 0 ? 'selected' : '') ?>>Fall</option>
<option value="Spring" <?= (strcasecmp($semVal, 'Spring') === 0 ? 'selected' : '') ?>>Spring</option>
</select>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-secondary btn-sm">Apply</button>
<a class="btn btn-outline-secondary btn-sm" href="?">Reset</a>
</div>
</form>
@@ -0,0 +1,62 @@
<div class="modal fade" id="assignStudentClassModal" tabindex="-1" aria-labelledby="assignStudentClassModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="assignStudentClassModalLabel">Assign Class to Student</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="assignStudentClassForm" action="<?= base_url('assign_class_student') ?>" method="post">
<?= csrf_field() ?>
<input type="hidden" name="student_id" id="studentId">
<div class="mb-3">
<label for="studentName" class="form-label">Student Name</label>
<input type="text" class="form-control" id="studentName" readonly>
</div>
<div class="mb-3">
<label for="student_class_section_id" class="form-label">Select Class</label>
<select name="class_section_id" id="student_class_section_id" class="form-control" required>
<option value="" disabled selected>Select a class</option>
<?php if (!empty($classes) && is_array($classes)): ?>
<?php foreach ($classes as $class_): ?>
<option value="<?= htmlspecialchars($class_['class_section_id']) ?>">
<?= htmlspecialchars($class_['class_section_name']) ?>
</option>
<?php endforeach; ?>
<?php else: ?>
<option value="" disabled>No classes available</option>
<?php endif; ?>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="assignStudentClassButton">Assign Class</button>
</div>
</div>
</div>
</div>
<?= $this->section('scripts') ?>
<script>
document.querySelectorAll('.assign-student-btn').forEach(function(button) {
button.addEventListener('click', function () {
const studentId = this.getAttribute('data-student-id');
const studentName = this.getAttribute('data-student-name');
document.getElementById('studentId').value = studentId;
document.getElementById('studentName').value = studentName;
});
});
document.getElementById('assignStudentClassButton').addEventListener('click', function() {
const form = document.getElementById('assignStudentClassForm');
if (form.checkValidity()) {
form.submit();
} else {
alert('Please select a class before submitting.');
}
});
</script>
<?= $this->endSection() ?>
@@ -0,0 +1,39 @@
<div class="modal fade" id="assignClassModal" tabindex="-1" aria-labelledby="assignClassModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="assignClassModalLabel">Assign Class</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="assignClassForm" action="/assign_class_teacher" method="post">
<input type="hidden" id="assignCsrfField" name="<?= esc(csrf_token()) ?>" value="<?= esc(csrf_hash()) ?>">
<input type="hidden" name="teacher_id" id="teacherId" value="">
<input type="hidden" name="teacher_role" id="teacherRoleHidden" value="">
<div class="mb-3">
<label for="teacherName" class="form-label">Name</label>
<input type="text" class="form-control" id="teacherName" readonly>
</div>
<div class="mb-3">
<label for="teacherRoleDisplay" class="form-label">Role</label>
<input type="text" class="form-control" id="teacherRoleDisplay" readonly>
</div>
<div class="mb-3">
<label for="class_section_id" class="form-label">Select Class</label>
<select name="class_section_id" id="class_section_id" class="form-control" required>
<option value="" disabled selected>Loading classes...</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" id="assignClassButton">Save</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,208 @@
<!-- app/Views/partials/attendance_notification_modal.php -->
<div class="modal fade" id="notificationModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form id="notificationForm">
<?= csrf_field() ?>
<input type="hidden" id="modalStudentId" name="student_id" value="">
<input type="hidden" id="modalDate" name="date" value="<?= esc(local_date(utc_now(), 'Y-m-d')) ?>">
<div class="modal-header">
<h5 class="modal-title">Notify Parent</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<!-- Recipient (editable) -->
<div class="mb-3">
<label class="form-label">To (Parent Email)</label>
<input type="email"
class="form-control"
id="parentEmail"
name="to"
required
autocomplete="email"
placeholder="parent@example.com"
list="parentEmailOptions">
<datalist id="parentEmailOptions"></datalist>
<div class="form-text" id="parentNameHelp"></div>
</div>
<!-- Subject Type -->
<div class="row g-3">
<div class="col-md-5">
<label class="form-label">Subject Type</label>
<select class="form-select" id="subjectType" name="subject_type" required>
<option value="Absent">Absent Notice</option>
<option value="Late">Late/Tardy Notice</option>
<option value="General">General Attendance Message</option>
</select>
</div>
<div class="col-md-7">
<label class="form-label">Subject</label>
<input type="text" class="form-control" id="notifySubject" name="subject" required>
</div>
</div>
<!-- Message -->
<div class="mt-3">
<label class="form-label">Message</label>
<textarea class="form-control" id="notifyMessage" name="message" rows="8" required></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" id="sendNotification" class="btn btn-primary">Send Notification</button>
</div>
</form>
</div>
</div>
</div>
<script>
// Templates in the partial for reuse
const formatNoticeDate = (value) => {
if (!value) return '';
const date = new Date(String(value).replace(' ', 'T'));
if (Number.isNaN(date.valueOf())) return String(value);
const pad = (num) => String(num).padStart(2, '0');
return `${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${date.getFullYear()}`;
};
const SUBJECT_TEMPLATES = {
Absent: (p) => {
const name = p.student_name || 'your child';
const date = p.date_fmt || formatNoticeDate(p.date) || '';
const cls = p.class_section_name ? ` (${p.class_section_name})` : '';
const reason = p.reason ? ` Reason: ${p.reason}.` : '';
const teacher = p.teacher_name ? `\nTeacher: ${p.teacher_name}` : '';
const school = p.school_name || 'Our School';
return `Dear Parent/Guardian,
This is to inform you that ${name}${cls} was marked Absent on ${date}.${reason}
If this was an error or there is additional context you would like to share, please reply to this email.
Thank you,
${school}${teacher}
`;
},
Late: (p) => {
const name = p.student_name || 'your child';
const date = p.date_fmt || formatNoticeDate(p.date) || '';
const cls = p.class_section_name ? ` (${p.class_section_name})` : '';
const reason = p.reason ? ` Reason: ${p.reason}.` : '';
const teacher = p.teacher_name ? `\nTeacher: ${p.teacher_name}` : '';
const school = p.school_name || 'Our School';
return `Dear Parent/Guardian,
This is to notify you that ${name}${cls} was marked Late on ${date}.${reason}
Please help ensure timely arrival. If you have questions, reply to this email.
Thank you,
${school}${teacher}
`;
},
General: (p) => {
const name = p.student_name || 'your child';
const date = p.date_fmt || formatNoticeDate(p.date) || '';
const cls = p.class_section_name ? ` (${p.class_section_name})` : '';
const teacher = p.teacher_name ? `\nTeacher: ${p.teacher_name}` : '';
const school = p.school_name || 'Our School';
return `Dear Parent/Guardian,
We are reaching out regarding ${name}${cls} on ${date}. Please see attendance details in the subject line.
If you have any questions, reply to this email.
Thank you,
${school}${teacher}
`;
}
};
window.buildSubject = function(subjectType, p) {
const base = p.student_name ? ` — ${p.student_name}` : '';
const dateLabel = p.date_fmt || formatNoticeDate(p.date);
const date = dateLabel ? ` (${dateLabel})` : '';
if (subjectType === 'Absent') return `Attendance Notice: Absent${base}${date}`;
if (subjectType === 'Late') return `Attendance Notice: Late${base}${date}`;
return `Attendance Notice${base}${date}`;
};
window.buildMessage = function(subjectType, payload) {
const fn = SUBJECT_TEMPLATES[subjectType] || SUBJECT_TEMPLATES.General;
return fn(payload);
};
</script>
<script>
(function () {
// Delegate so it always works, even if the modal is re-rendered
document.addEventListener('click', async function (e) {
if (!e.target || e.target.id !== 'sendNotification') return;
const form = document.getElementById('notificationForm');
if (!form) { console.error('notificationForm not found'); return; }
const toEl = document.getElementById('parentEmail');
const subjEl = document.getElementById('notifySubject');
const msgEl = document.getElementById('notifyMessage');
if (!toEl || !subjEl || !msgEl) {
console.error('Missing email/subject/message fields in the modal.');
alert('Missing fields in the modal.');
return;
}
// Basic front-end validation
if (!toEl.value.trim()) { alert('Please enter parent email'); return; }
if (!subjEl.value.trim()) { alert('Please enter a subject'); return; }
if (!msgEl.value.trim()) { alert('Please enter a message'); return; }
const formData = new FormData(form);
try {
const resp = await fetch('<?= base_url('attendance/notify_parent') ?>', {
method: 'POST',
body: formData,
headers: { 'Accept': 'application/json' }
});
// If server crashed and returned HTML, this will throw:
let data;
try { data = await resp.json(); }
catch (jsonErr) {
const text = await resp.text();
console.error('Non-JSON response', text);
alert('Server error (non-JSON). Check logs.');
return;
}
if (!resp.ok || !data || !data.success) {
console.error('Notify failed', data);
alert('Failed to send: ' + (data && data.message ? data.message : 'Unknown error'));
return;
}
alert('Notification sent successfully');
const modalEl = document.getElementById('notificationModal');
if (modalEl) {
const inst = bootstrap.Modal.getInstance(modalEl) || new bootstrap.Modal(modalEl);
inst.hide();
}
// If CSRF rotates, update hidden input
if (data.csrf) {
const [name, value] = Object.entries(data.csrf)[0];
const tokenInput = form.querySelector('input[name="'+name+'"]');
if (tokenInput) tokenInput.value = value;
}
} catch (err) {
console.error('Fetch error', err);
alert('Network or server error. See console for details.');
}
});
})();
</script>
+171
View File
@@ -0,0 +1,171 @@
<?php
// Compute user info and roles
$userName = trim((string) (session()->get('user_name') ?? ''));
$userEmail = trim((string) (session()->get('user_email') ?? ''));
$roleStr = strtolower((string) (session()->get('role') ?? 'guest'));
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
$otherRoles = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $roleStr));
// Initials for avatar
$initials = 'U';
if ($userName !== '') {
$parts = preg_split('/\s+/', $userName);
$first = $parts[0] ?? '';
$last = count($parts) > 1 ? end($parts) : '';
$initials = strtoupper(substr($first, 0, 1) . ($last !== '' ? substr($last, 0, 1) : ''));
} elseif ($userEmail !== '') {
$initials = strtoupper(substr($userEmail, 0, 1));
}
// Style config and current selections
$styleCfg = config('Style');
$sess = session();
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
if ($currentMenu === 'custom') {
$menuLP = [
'bg' => (string)($sess->get('menu_custom_bg') ?? '#0f172a'),
'text' => (string)($sess->get('menu_custom_text') ?? '#ffffff'),
'mode' => (string)($sess->get('menu_custom_mode') ?? 'dark'),
];
} else {
$menuLP = $styleCfg->menuPalettes[$currentMenu] ?? ($styleCfg->menuPalettes[$styleCfg->defaultMenu] ?? [
'bg' => '#ffffff', 'text' => '#334155', 'mode' => 'light']);
}
?>
<a class="nav-link p-0" href="#" id="quickMenu" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" aria-label="Open user menu">
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center" style="width: 40px; height: 40px; background-color: var(--mgmt-primary);">
<?= esc($initials) ?>
</div>
<span class="visually-hidden">User menu</span>
<span class="dropdown-toggle ms-1" style="font-size:0; line-height:0;"> </span>
</a>
<div class="dropdown-menu dropdown-menu-end quick-menu" aria-labelledby="quickMenu" style="max-height: 70vh; overflow-y: auto; overflow-x: hidden; min-width: 260px; max-width: min(320px, calc(100vw - 16px)); right: 8px; left: auto;">
<div class="px-3 py-3 d-flex align-items-center">
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center me-3" style="width: 36px; height: 36px; background-color: var(--mgmt-primary);">
<?= esc($initials) ?>
</div>
<div>
<div class="fw-semibold mb-0" style="line-height: 1.2;">
<?= esc($userName !== '' ? $userName : 'User') ?>
</div>
<div class="text-muted small" style="line-height: 1.2;">
<?= esc($roleStr) ?><?= $userEmail ? ' · ' . esc($userEmail) : '' ?>
</div>
</div>
</div>
<div class="dropdown-divider"></div>
<?php if (!empty($otherRoles)): ?>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddRoleMenu" role="button" aria-expanded="false" aria-controls="ddRoleMenu">
Switch Role <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse" id="ddRoleMenu">
<div class="px-2 pb-2">
<?php foreach ($otherRoles as $r): ?>
<form method="post" action="<?= site_url('set-role') ?>" class="mb-1">
<?= csrf_field() ?>
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
</form>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<?php endif; ?>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddStyleMenu" role="button" aria-expanded="false" aria-controls="ddStyleMenu">
Style <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse" id="ddStyleMenu">
<div class="px-2 pb-2">
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddAccentMenu" role="button" aria-expanded="true" aria-controls="ddAccentMenu">
Accent <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse show" id="ddAccentMenu">
<div class="px-2 pb-2">
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentAccent); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?accent=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<div class="px-2 small text-muted">Menu</div>
<div class="px-2 pb-2">
<div class="table-responsive">
<table class="table table-borderless mb-2" style="min-width:auto;">
<tbody>
<?php
$palettes = $styleCfg->menuPalettes ?? [];
$keys = array_keys($palettes);
$cols = 3; $i = 0;
foreach ($keys as $k):
if ($i % $cols === 0) echo '<tr>';
$pal = $palettes[$k];
$bg = (string)($pal['bg'] ?? '#fff');
$tx = (string)($pal['text'] ?? '#000');
$active = ($k === $currentMenu) ? 'outline-success' : 'outline-secondary';
?>
<td class="p-1" style="width:33.33%;">
<a href="<?= site_url('ui/style?menu=' . urlencode($k) . '&back=' . urlencode(current_url())) ?>" class="btn btn-<?= $active ?> w-100" style="padding:6px;">
<div class="rounded" style="height:28px; background-color: <?= esc($bg) ?>; color: <?= esc($tx) ?>; display:flex; align-items:center; justify-content:center; font-size:.8rem;">
<?= ucfirst(esc($k)) ?>
</div>
</a>
</td>
<?php
$i++;
if ($i % $cols === 0) echo '</tr>';
endforeach;
if ($i % $cols !== 0) { while ($i % $cols !== 0) { echo '<td class="p-1"></td>'; $i++; } echo '</tr>'; }
?>
</tbody>
</table>
</div>
<!-- Custom color picker -->
<form action="<?= site_url('ui/style') ?>" method="get" class="px-1">
<input type="hidden" name="menu" value="custom">
<input type="hidden" name="back" value="<?= esc(current_url()) ?>">
<div class="row g-2 align-items-center">
<div class="col-6">
<label class="form-label mb-1 small">Menu BG</label>
<input type="color" name="menu_bg" value="<?= esc($menuLP['bg'] ?? '#0f172a') ?>" class="form-control form-control-color w-100" title="Pick background color">
</div>
<div class="col-6">
<label class="form-label mb-1 small">Text</label>
<input type="color" name="menu_text" value="<?= esc($menuLP['text'] ?? '#ffffff') ?>" class="form-control form-control-color w-100" title="Pick text color">
</div>
<div class="col-12">
<label class="form-label mb-1 small">Mode</label>
<div>
<?php $modeLP = ($menuLP['mode'] ?? 'light'); ?>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mm_light" value="light" <?= $modeLP==='light'?'checked':'' ?>>
<label class="form-check-label" for="mm_light">Light</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mm_dark" value="dark" <?= $modeLP==='dark'?'checked':'' ?>>
<label class="form-check-label" for="mm_dark">Dark</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mm_auto" value="auto" <?= ($modeLP!=='light' && $modeLP!=='dark')?'checked':'' ?>>
<label class="form-check-label" for="mm_auto">Auto</label>
</div>
</div>
</div>
<div class="col-12 mt-1">
<button type="submit" class="btn btn-sm btn-primary w-100">Apply Custom</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="<?= base_url('/logout') ?>">Log Out</a>
</div>
@@ -0,0 +1,37 @@
<div class="emergency-contact-form border rounded p-3 mb-3 bg-white shadow-sm">
<h5 class="mb-3 text-primary">Emergency Contact Information</h5>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">First Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="emergency_firstname[]" required data-base-name="emergency_firstname" maxlength="30">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Last Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="emergency_lastname[]" required data-base-name="emergency_lastname" maxlength="30">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Phone Number <span class="text-danger">*</span></label>
<input type="tel" class="form-control" id="phoneInput" name="emergency_phone[]" required data-base-name="emergency_phone" maxlength="12">
<div id="validationStatus" class="validation-status">
</div>
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Relationship to Student(s) <span class="text-danger">*</span></label>
<select class="form-select" name="emergency_relation[]" required data-base-name="emergency_relation">
<option value="">Select Relationship</option>
<option value="Parent">Parent</option>
<option value="Sibling">Sibling</option>
<option value="Relative">Relative</option>
<option value="Friend">Friend</option>
<option value="Neighbor">Neighbor</option>
<option value="Guardian">Guardian</option>
<option value="Other">Other</option>
</select>
</div>
</div>
</div>
+26
View File
@@ -0,0 +1,26 @@
<!-- Flash Messages -->
<?php foreach (['success', 'error', 'info', 'warning'] as $type): ?>
<?php if (session()->getFlashdata($type)): ?>
<div class="alert alert-<?= esc($type) ?> alert-dismissible fade show" role="alert">
<?= session()->getFlashdata($type) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php endforeach; ?>
<!-- Auto-hide Flash Messages -->
<script>
document.addEventListener('DOMContentLoaded', function () {
const alerts = document.querySelectorAll('.alert');
alerts.forEach(function (alert) {
setTimeout(() => {
alert.classList.add('fade');
alert.classList.remove('show');
setTimeout(() => {
alert.remove();
}, 500);
}, 4000);
});
});
</script>
+94
View File
@@ -0,0 +1,94 @@
<?php
$userRole = session()->get('role'); // assuming you store it as 'role'
$quickTourUrl = base_url('/help_center'); // default
switch ($userRole) {
case 'parent':
$quickTourUrl = base_url('/parent');
break;
case 'teacher':
$quickTourUrl = base_url('/teacher');
break;
case 'teacher_assistant':
$quickTourUrl = base_url('/teacher');
break;
}
?>
<link rel="stylesheet" href="<?= base_url('assets/css/landing_page.css') ?>">
<footer class="footer mt-auto custom-footer text-white py-4">
<div class="container">
<div class="row align-items-start justify-content-between">
<!-- Contact Info -->
<div class="col-md-6 col-12 mb-3 mb-md-0 text-md-start">
<ul class="list-unstyled mb-0 info-list">
<li class="info-title"></li>
<li><i class="fa fa-map-marker-alt me-2"></i>5 Courthouse Lane, Chelmsford, MA 01824</li>
<li><i class="fa fa-phone-alt me-2"></i>+1 978-364-0219</li>
<li><i class="fa fa-envelope me-2"></i>alrahma.isgl@gmail.com</li>
</ul>
</div>
<!-- Policy Links: centered on small, right on md+ -->
<div class="col-md-4 col-12 text-center text-md-end">
<ul class="list-unstyled mb-0 info-list">
<li class="info-title text-center text-md-end"></li>
<li>
<a href="<?= base_url('privacy_policy.pdf') ?>" target="_blank" rel="noopener noreferrer"
class="pdf-link" data-filename="privacy_policy.pdf">
<i class="fas fa-file-pdf me-1"></i>Privacy Policy
</a>
</li>
<li>
<a href="<?= base_url('terms_of_service.pdf') ?>" target="_blank" rel="noopener noreferrer"
class="pdf-link" data-filename="terms_of_service.pdf">
<i class="fas fa-file-pdf me-1"></i>Terms of Service
</a>
</li>
<li>
<a href="<?= base_url('account_creation_guide.pdf') ?>" target="_blank" rel="noopener noreferrer"
class="pdf-link" data-filename="account_creation_guide.pdf">
<i class="fas fa-file-pdf"></i>How To Create An Account
</a>
</li>
</ul>
</div>
</div>
</div>
<br>
<p class="text-center text-white">© 2026 Al Rahma Sunday School by ISGL. All Rights Reserved.</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check if PDF files exist and add error handling
document.querySelectorAll('.pdf-link').forEach(link => {
const pdfUrl = link.getAttribute('href');
// Test if the PDF exists
fetch(pdfUrl, {
method: 'HEAD'
})
.then(response => {
if (!response.ok) {
// File doesn't exist or is inaccessible
link.style.opacity = '0.7';
link.title = 'File might be temporarily unavailable';
console.warn('PDF might be missing:', pdfUrl);
// Modify click behavior to show helpful message
link.addEventListener('click', function(e) {
if (!confirm('The PDF file might be temporarily unavailable. Try to open it anyway?')) {
e.preventDefault();
}
});
}
})
.catch(error => {
console.error('Error checking PDF:', pdfUrl, error);
link.style.opacity = '0.7';
link.title = 'File check failed';
});
});
});
</script>
+5
View File
@@ -0,0 +1,5 @@
<footer class="footer bg-white text-muted border-top">
<div class="container py-3">
<p class="text-center mb-0">© 2026 Al Rahma Sunday School by <a class="text-decoration-underline" href="https://isgl.org" target="_blank" rel="noopener noreferrer">ISGL</a>. All Rights Reserved.</p>
</div>
</footer>
+38
View File
@@ -0,0 +1,38 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Al Rahma Sunday School</title>
<meta name="keywords" content="">
<meta name="description" content="">
<!-- Favicon -->
<link rel="icon" href="<?= base_url('assets/images/favicon.ico') ?>">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css">
<!-- Google Web Fonts -->
<!--link rel="preconnect" href="https://fonts.googleapis.com"-->
<!--link rel="preconnect" href="https://fonts.gstatic.com" crossorigin-->
<!--link
href="https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;600&family=Inter:wght@600&family=Lobster+Two:wght@700&display=swap"
rel="stylesheet"-->
<!-- Icon Font Stylesheets -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.0/css/all.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.7.2/font/bootstrap-icons.min.css"
rel="stylesheet">
<!-- Libraries Stylesheets -->
<link href="<?= base_url('lib/animate/animate.min.css') ?>" rel="stylesheet">
<link href="<?= base_url('lib/owlcarousel/assets/owl.carousel.min.css') ?>" rel="stylesheet">
<!-- Custom Stylesheets -->
<link rel="stylesheet" href="<?= base_url('css/style.css') ?>">
<link rel="stylesheet" href="<?= base_url('assets/css/landing_page.css') ?>">
<link rel="stylesheet" href="<?= base_url('assets/css/custom.css') ?>">
</head>
+32
View File
@@ -0,0 +1,32 @@
<head>
<!-- Meta Information -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Al Rahma Sunday School</title>
<!-- Favicon -->
<link rel="icon" href="<?= base_url('assets/images/favicon.ico') ?>" type="image/x-icon">
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;600&family=Inter:wght@600&family=Lobster+Two:wght@700&display=swap" rel="stylesheet">
<!-- Icon Fonts -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.0/css/all.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.7.2/font/bootstrap-icons.min.css">
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- External Libraries CSS -->
<link rel="stylesheet" href="<?= base_url('lib/owlcarousel/assets/owl.carousel.min.css') ?>">
<!-- DataTables CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css">
<!-- Custom Styles (if any) -->
<link rel="stylesheet" href="<?= base_url('css/bootstrap.min.css') ?>">
</head>
+108
View File
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.7.2/font/bootstrap-icons.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Al Rahma Sunday School</title>
<!-- Favicon -->
<link href="<?= base_url('assets/images/favicon.ico') ?>" rel="icon">
<link rel="stylesheet" href="<?= base_url('assets/css/custom.css') ?>">
<!-- In <head> -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
</head>
<body>
<?php
// Check if session is already started
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user_id'])) {
echo "<p>User not logged in</p>";
exit;
}
$userId = $_SESSION['user_id'];
// Include the shared database connection file
$file = __DIR__ . '/../../db_connection.php'; // Adjust the relative path as needed
if (file_exists($file)) {
require_once $file;
} else {
die("Error: Could not find the required file '$file'.");
}
// Check if the connection is established
if (!isset($conn)) {
die("Error: Database connection not established.");
}
// Fetch user data from the database
$sql = "SELECT firstname, lastname FROM users WHERE id = ?";
$stmt = $conn->prepare($sql);
if (!$stmt) {
die('Failed to prepare statement: ' . $conn->error);
}
$stmt->bind_param("i", $userId);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
if ($user) {
$userName = $user['firstname'] . ' ' . $user['lastname'];
$userInitials = $user['firstname'][0] . $user['lastname'][0];
} else {
$userName = 'User not found';
$userInitials = '??';
}
$stmt->close();
$conn->close();
?>
<header class="navbar navbar-dark sticky-top flex-md-nowrap shadow" style="background-color: #2c9b09;">
<div class="top-right">
<div class="dropdown dropdown-hover">
<div class="profile-picture" id="profile-picture">
<span id="userInitials">
<?php echo htmlspecialchars($userInitials); ?>
</span>
</div>
<div class="dropdown-menu dropdown-menu-right">
<div class="profile-details">
<div id="user-name">
<?php echo htmlspecialchars($userName); ?>
</div>
<div><a class="dropdown-item"
href="<?= base_url('/profile/' . session()->get('user_id')) ?>">Profile</a>
</div>
<div><a class="dropdown-item"
href="<?= base_url('/preferences/' . session()->get('user_id')) ?>">Preferences</a>
</div>
<div class="dropdown-divider"></div>
<button class="btn btn-outline-dark sign-out-btn"
onclick="window.location.href='<?= base_url('/logout'); ?>'">Log Out</button>
</div>
</div>
</div>
</div>
<a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">
Al Rahma Sunday School </a>
</header>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
</body>
</html>
+204
View File
@@ -0,0 +1,204 @@
<?php
// Build user display and menu data
$userName = trim((string) (session()->get('user_name') ?? ''));
$userEmail = trim((string) (session()->get('user_email') ?? ''));
$rawRole = session()->get('role');
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
$currentRole = strtolower((string) ($rawRole ?? 'guest'));
$otherRoles = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $currentRole));
// Compute initials from name, fallback to email/letter U
$initials = 'U';
if ($userName !== '') {
$parts = preg_split('/\s+/', $userName);
$first = $parts[0] ?? '';
$last = count($parts) > 1 ? end($parts) : '';
$initials = strtoupper(substr($first, 0, 1) . ($last !== '' ? substr($last, 0, 1) : ''));
} elseif ($userEmail !== '') {
$initials = strtoupper(substr($userEmail, 0, 1));
}
// Style palettes
$styleCfg = config('Style');
$sess = session();
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
// Build current menu palette (supports custom)
if ($currentMenu === 'custom') {
$menuLP = [
'bg' => (string)($sess->get('menu_custom_bg') ?? '#0f172a'),
'text' => (string)($sess->get('menu_custom_text') ?? '#ffffff'),
'mode' => (string)($sess->get('menu_custom_mode') ?? 'dark'),
];
} else {
$menuLP = $styleCfg->menuPalettes[$currentMenu] ?? ($styleCfg->menuPalettes[$styleCfg->defaultMenu] ?? [
'bg' => '#ffffff', 'text' => '#334155', 'mode' => 'light']);
}
$resolveMenuMode = function (string $mode, string $bg): string {
$mode = strtolower(trim($mode));
if ($mode === 'light' || $mode === 'dark') return $mode;
$hex = ltrim(trim($bg), '#');
if (strlen($hex) === 3) {
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
}
if (strlen($hex) !== 6) return 'dark';
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
$lum = (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255.0;
return ($lum < 0.5) ? 'dark' : 'light';
};
$headerMode = $resolveMenuMode((string)($menuLP['mode'] ?? 'light'), (string)($menuLP['bg'] ?? '#0f172a'));
$headerModeCls = ($headerMode === 'dark') ? 'navbar-dark' : 'navbar-light';
?>
<header class="navbar <?= esc($headerModeCls) ?> sticky-top bg-white border-bottom flex-md-nowrap p-0 shadow-sm">
<div class="d-flex align-items-center w-100">
<!-- Brand (left) -->
<a class="navbar-brand col-md-3 col-lg-2 mr-0 px-1" href="/administrator/administratordashboard">
<img src="<?= base_url('assets/images/logo.png') ?>" alt="School Icon" style="width: 50px; height: 40px; margin-right: 8px;">
<strong>School Management Dashboard</strong>
</a>
<!-- Spacer pushes avatar to the right -->
<div class="ms-auto"></div>
<!-- Gmail-like avatar with initials (top-right) -->
<div class="dropdown me-2">
<button class="btn p-0 bg-transparent border-0" id="userAvatarMenu" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" aria-label="Open user menu">
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center"
style="width: 40px; height: 40px; background-color: var(--mgmt-primary);">
<?= esc($initials) ?>
</div>
</button>
<div class="dropdown-menu dropdown-menu-end p-0" aria-labelledby="userAvatarMenu" style="min-width: 260px;">
<div class="px-3 py-3 d-flex align-items-center">
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center me-3"
style="width: 36px; height: 36px; background-color: var(--mgmt-primary);">
<?= esc($initials) ?>
</div>
<div>
<div class="fw-semibold mb-0" style="line-height: 1.2;">
<?= esc($userName !== '' ? $userName : 'User') ?>
</div>
<div class="text-muted small" style="line-height: 1.2;">
<?= esc($currentRole) ?><?= $userEmail ? ' · ' . esc($userEmail) : '' ?>
</div>
</div>
</div>
<div class="dropdown-divider"></div>
<?php if (!empty($otherRoles)): ?>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddRoleBody" role="button" aria-expanded="false" aria-controls="ddRoleBody">
Switch Role <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse" id="ddRoleBody">
<div class="px-2 pb-2">
<?php foreach ($otherRoles as $r): ?>
<form method="post" action="<?= site_url('set-role') ?>" class="mb-1">
<?= csrf_field() ?>
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
</form>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<?php endif; ?>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddStyleBody" role="button" aria-expanded="false" aria-controls="ddStyleBody">
Style <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse" id="ddStyleBody">
<div class="px-2 pb-2">
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddAccentBody" role="button" aria-expanded="true" aria-controls="ddAccentBody">
Accent <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse show" id="ddAccentBody">
<div class="px-2 pb-2">
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentAccent); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?accent=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<div class="px-2 small text-muted">Menu</div>
<div class="px-2 pb-2">
<div class="table-responsive">
<table class="table table-borderless mb-2" style="min-width:auto;">
<tbody>
<?php
$palettes = $styleCfg->menuPalettes ?? [];
$keys = array_keys($palettes);
$cols = 3; $i = 0;
foreach ($keys as $k):
if ($i % $cols === 0) echo '<tr>';
$pal = $palettes[$k];
$bg = (string)($pal['bg'] ?? '#fff');
$tx = (string)($pal['text'] ?? '#000');
$active = ($k === $currentMenu) ? 'outline-success' : 'outline-secondary';
?>
<td class="p-1" style="width:33.33%;">
<a href="<?= site_url('ui/style?menu=' . urlencode($k) . '&back=' . urlencode(current_url())) ?>" class="btn btn-<?= $active ?> w-100" style="padding:6px;">
<div class="rounded" style="height:28px; background-color: <?= esc($bg) ?>; color: <?= esc($tx) ?>; display:flex; align-items:center; justify-content:center; font-size:.8rem;">
<?= ucfirst(esc($k)) ?>
</div>
</a>
</td>
<?php
$i++;
if ($i % $cols === 0) echo '</tr>';
endforeach;
if ($i % $cols !== 0) { while ($i % $cols !== 0) { echo '<td class="p-1"></td>'; $i++; } echo '</tr>'; }
?>
</tbody>
</table>
</div>
<!-- Custom color picker -->
<form action="<?= site_url('ui/style') ?>" method="get" class="px-1">
<input type="hidden" name="menu" value="custom">
<input type="hidden" name="back" value="<?= esc(current_url()) ?>">
<div class="row g-2 align-items-center">
<div class="col-6">
<label class="form-label mb-1 small">Menu BG</label>
<input type="color" name="menu_bg" value="<?= esc($menuLP['bg'] ?? '#0f172a') ?>" class="form-control form-control-color w-100" title="Pick background color">
</div>
<div class="col-6">
<label class="form-label mb-1 small">Text</label>
<input type="color" name="menu_text" value="<?= esc($menuLP['text'] ?? '#ffffff') ?>" class="form-control form-control-color w-100" title="Pick text color">
</div>
<div class="col-12">
<label class="form-label mb-1 small">Mode</label>
<div>
<?php $modeLP = ($menuLP['mode'] ?? 'light'); ?>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mg_mm_light" value="light" <?= $modeLP==='light'?'checked':'' ?>>
<label class="form-check-label" for="mg_mm_light">Light</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mg_mm_dark" value="dark" <?= $modeLP==='dark'?'checked':'' ?>>
<label class="form-check-label" for="mg_mm_dark">Dark</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mg_mm_auto" value="auto" <?= ($modeLP!=='light' && $modeLP!=='dark')?'checked':'' ?>>
<label class="form-check-label" for="mg_mm_auto">Auto</label>
</div>
</div>
</div>
<div class="col-12 mt-1">
<button type="submit" class="btn btn-sm btn-primary w-100">Apply Custom</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="<?= base_url('/logout') ?>">Log Out</a>
</div>
</div>
</div>
</header>
+695
View File
@@ -0,0 +1,695 @@
<?php
// Get and normalize the role
$rawRole = session()->get('role');
if (is_array($rawRole)) {
$rawRole = $rawRole[0] ?? 'guest';
}
$role = strtolower((string)($rawRole ?? 'guest'));
// Set dashboard path based on role
switch ($role) {
case 'parent':
$dashboard = base_url('/parent_dashboard');
break;
case 'teacher':
$dashboard = base_url('/teacher_dashboard');
break;
case 'teacher_assistant':
$dashboard = base_url('/teacher_dashboard');
break;
case 'student':
$dashboard = base_url('/landing_page/student_dashboard');
break;
case 'guest':
$dashboard = base_url('/landing_page/guest_dashboard');
break;
default:
$dashboard = base_url('/login');
break;
}
?>
<?php
// Build user display (avatar initials + info)
$userName = trim((string) (session()->get('user_name') ?? ''));
$userEmail = trim((string) (session()->get('user_email') ?? ''));
$initials = 'U';
if ($userName !== '') {
$parts = preg_split('/\s+/', $userName);
$first = $parts[0] ?? '';
$last = count($parts) > 1 ? end($parts) : '';
$initials = strtoupper(substr($first, 0, 1) . ($last !== '' ? substr($last, 0, 1) : ''));
} elseif ($userEmail !== '') {
$initials = strtoupper(substr($userEmail, 0, 1));
}
// Score card picker (parent/teacher only)
$scoreCardStudents = [];
$scoreCardEnabledRole = in_array($role, ['parent', 'parent_dashboard', 'teacher', 'teacher_assistant', 'teacher_dashboard'], true);
if ($scoreCardEnabledRole) {
try {
$studentModel = new \App\Models\StudentModel();
if (in_array($role, ['parent', 'parent_dashboard'], true)) {
$parentId = (int)(session()->get('user_id') ?? 0);
if ($parentId > 0) {
$scoreCardStudents = $studentModel
->select('id, school_id, firstname, lastname')
->where('parent_id', $parentId)
->orderBy('lastname', 'ASC')
->orderBy('firstname', 'ASC')
->findAll();
}
} else {
$configModel = new \App\Models\ConfigurationModel();
$schoolYear = session()->get('school_year') ?? $configModel->getConfig('school_year');
$classSectionId = (int)($class_section_id ?? session()->get('class_section_id') ?? 0);
if ($classSectionId > 0 && !empty($schoolYear)) {
$scoreCardStudents = $studentModel->getByClassAndYear($classSectionId, $schoolYear);
}
if (empty($scoreCardStudents)) {
$userId = (int)(session()->get('user_id') ?? 0);
if ($userId > 0 && !empty($schoolYear)) {
$db = \Config\Database::connect();
$sectionRows = $db->table('teacher_class')
->select('class_section_id')
->where('teacher_id', $userId)
->where('school_year', (string)$schoolYear)
->get()
->getResultArray();
$sectionIds = array_values(array_filter(array_unique(array_map(
static fn($r) => (int)($r['class_section_id'] ?? 0),
$sectionRows
)), static fn($v) => $v > 0));
if (!empty($sectionIds)) {
$studentClassModel = new \App\Models\StudentClassModel();
$rows = $studentClassModel->getStudentsByClassSectionIds($sectionIds);
$unique = [];
foreach ($rows as $r) {
$sid = (int)($r['student_id'] ?? 0);
if ($sid > 0) {
$unique[$sid] = [
'id' => $sid,
'school_id' => $r['school_id'] ?? '',
'firstname' => $r['firstname'] ?? '',
'lastname' => $r['lastname'] ?? '',
];
}
}
$scoreCardStudents = array_values($unique);
}
}
}
}
} catch (\Throwable $e) {
$scoreCardStudents = [];
}
}
?>
<style>
@media (max-width: 576px) {
.mobile-adjust {
margin-right: 5px !important;
transform: translateX(-10px);
}
}
/* Collapse fills remaining space */
.navbar-collapse-center { flex: 1 1 auto; }
/* At lg+, center only the main nav items while avatar stays right */
@media (min-width: 992px) {
.navbar-collapse-center { display: flex; align-items: center; flex-wrap: wrap; }
.navbar-collapse-center .nav-center { margin-left: auto; margin-right: auto; }
}
.role-nav-grid {
display: flex;
flex-wrap: nowrap;
gap: 0.15rem;
justify-content: flex-start;
align-items: stretch;
width: 100%;
margin-top: 0.15rem;
padding-bottom: 0.15rem;
overflow-x: auto;
-ms-overflow-style: none;
scrollbar-width: none;
}
.role-nav-grid::-webkit-scrollbar {
display: none;
}
.role-nav-link {
position: relative;
flex: 0 0 auto;
max-width: 8rem;
min-width: 6rem;
padding: 0.2rem 0.4rem;
border-radius: 0.6rem;
border: 1px solid rgba(255, 255, 255, 0.35);
background: transparent;
color: inherit;
text-decoration: none;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
line-height: 1;
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
box-shadow: none;
}
.navbar.navbar-dark .role-nav-link {
border-color: rgba(255, 255, 255, 0.6);
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.25);
}
.navbar.navbar-light .role-nav-link {
border-color: rgba(15, 23, 42, 0.35);
color: #0d2c54;
box-shadow: 0 4px 8px rgba(15, 23, 42, 0.12);
}
.role-nav-link:hover,
.role-nav-link:focus {
transform: translateY(-2px);
border-color: rgba(255, 255, 255, 0.6);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.15);
text-decoration: none;
}
.role-nav-icon {
font-size: 1.1rem;
margin-bottom: 0.1rem;
display: inline-flex;
align-items: center;
justify-content: center;
}
.role-nav-label {
font-size: 0.75rem;
font-weight: 500;
line-height: 1;
}
.role-nav-badge {
position: absolute;
top: 0.45rem;
right: 0.45rem;
font-size: 0.65rem;
font-weight: 600;
padding: 0.25rem 0.45rem;
border-radius: 999px;
background: #d92b2b;
color: #fff;
}
@media (max-width: 992px) {
.role-nav-link {
min-width: 6rem;
max-width: 7.5rem;
}
}
@media (max-width: 768px) {
.role-nav-grid {
flex-wrap: wrap;
justify-content: center;
gap: 0.2rem;
overflow-x: visible;
}
.role-nav-link {
flex: 1 1 calc(50% - 0.3rem);
max-width: calc(50% - 0.3rem);
min-width: 0;
}
}
@media (max-width: 576px) {
.role-nav-link {
min-width: 6.2rem;
}
}
</style>
<?php
// Read menu mode to set appropriate navbar-* class for contrast parity with admin
$styleCfg = config('Style');
$sess = session();
$menuKeyLP = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
if ($menuKeyLP === 'custom') {
$menuMode = (string)($sess->get('menu_custom_mode') ?? 'auto');
$menuBg = (string)($sess->get('menu_custom_bg') ?? '#0f172a');
$resolveMenuMode = function (string $mode, string $bg): string {
$mode = strtolower(trim($mode));
if ($mode === 'light' || $mode === 'dark') return $mode;
$hex = ltrim(trim($bg), '#');
if (strlen($hex) === 3) {
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
}
if (strlen($hex) !== 6) return 'dark';
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
$lum = (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255.0;
return ($lum < 0.5) ? 'dark' : 'light';
};
$menuModeEffective = $resolveMenuMode($menuMode, $menuBg);
$navModeCls = ($menuModeEffective === 'dark') ? 'navbar-dark' : 'navbar-light';
} else {
$menuLP = $styleCfg->menuPalettes[$menuKeyLP] ?? ($styleCfg->menuPalettes[$styleCfg->defaultMenu] ?? ['mode' => 'light']);
$navModeCls = (isset($menuLP['mode']) && $menuLP['mode'] === 'dark') ? 'navbar-dark' : 'navbar-light';
}
// Provide active event count for parent role if not already injected by the controller
if (!isset($activeEventCount) && ($role ?? '') === 'parent') {
$configModel = new \App\Models\ConfigurationModel();
$eventModel = new \App\Models\EventModel();
$year = $sess->get('school_year') ?? $configModel->getConfig('school_year');
$semester = $sess->get('semester') ?? $configModel->getConfig('semester');
$activeEventCount = count($eventModel->getActiveEvents($year, $semester) ?? []);
}
?>
<nav class="navbar navbar-expand-lg <?= esc($navModeCls) ?> sticky-top shadow custom-navbar">
<a href="<?= $dashboard ?>" class="navbar-brand d-flex align-items-center ms-3">
<img src="<?= base_url('assets/images/logo.png') ?>" alt="School Logo" class="navbar-logo">
</a>
<button class="navbar-toggler order-0 me-2 mobile-adjust" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- collapse takes remaining width; ms-lg-3 adds a small gap from logo at lg+ -->
<div class="collapse navbar-collapse navbar-collapse-center ms-lg-auto" id="navbarCollapse">
<div class="navbar-nav d-flex nav-center">
<?php if ($role !== 'parent' && $role !== 'teacher' && $role !== 'teacher_assistant'): ?>
<a href="<?= $dashboard ?>" data-bs-toggle="tooltip" data-bs-placement="bottom" title="View a summary of key school statistics, recent activities and important updates." class="nav-item nav-link fs-5 bi bi-house-door"> Dashboard</a>
<?php endif; ?>
<?php if ($role === 'parent'): ?>
<?php
$parentLinks = [
[
'href' => $dashboard,
'icon' => 'bi-house-door',
'label' => 'Dashboard',
'title' => 'View a summary of key school statistics, recent activities and important updates.',
],
[
'href' => base_url('/parent/child_register'),
'icon' => 'bi-person-plus',
'label' => 'Register Students',
'title' => 'Add your child(ren) to the schools database and update their basic info.',
],
[
'href' => base_url('/parent/enroll_classes'),
'icon' => 'bi-pencil-square',
'label' => 'Enroll in Classes',
'title' => 'Enroll registered students in their appropriate grade level or course.',
],
[
'href' => base_url('/parent/invoice_payment'),
'icon' => 'bi-credit-card',
'label' => 'Invoice',
'title' => 'View and pay your child(ren)\'s invoice securely (tuition & events).',
],
[
'href' => base_url('/parent/attendance'),
'icon' => 'bi-calendar-check',
'label' => 'Attendance',
'title' => 'Track attendance record of your child(ren) (absences & late arrivals).',
],
[
'href' => base_url('parent/report-attendance'),
'icon' => 'bi-megaphone',
'label' => 'Report Absence',
'title' => 'Let the school know about an absence, late arrival, or early dismissal.',
],
[
'href' => base_url('/parent/scores'),
'icon' => 'bi-clipboard-data',
'label' => 'Scores',
'title' => 'Review progressive academic score for the year (homeworks, projects and exams).',
],
[
'href' => base_url('/parent/progress'),
'icon' => 'bi-journal-check',
'label' => 'Class Progress',
'title' => 'View weekly class progress shared by teachers.',
],
[
'href' => base_url('/parent/events'),
'icon' => 'bi-bell',
'label' => 'Events',
'title' => 'Manage participation in planned school activities such as field trips or competitions.',
'badge' => !empty($activeEventCount) ? $activeEventCount : null,
],
[
'href' => base_url('/parent/calendar'),
'icon' => 'bi-calendar-day',
'label' => 'Calendar',
'title' => 'View school-wide calendar of classes, events and holidays.',
],
];/*
if ($scoreCardEnabledRole) {
$parentLinks[] = [
'href' => base_url('student/score-card/list'),
'icon' => 'bi-card-list',
'label' => 'Score Card',
'title' => 'Open a student score card.',
];
}*/
usort($parentLinks, static function ($a, $b) {
$la = strtolower((string)($a['label'] ?? ''));
$lb = strtolower((string)($b['label'] ?? ''));
if ($la === 'dashboard' && $lb !== 'dashboard') return -1;
if ($lb === 'dashboard' && $la !== 'dashboard') return 1;
return strcasecmp($la, $lb);
});
?>
<div class="role-nav-grid">
<?php foreach ($parentLinks as $link): ?>
<?php $badge = $link['badge'] ?? null; ?>
<a href="<?= esc($link['href']) ?>"
class="nav-item nav-link role-nav-link"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="<?= esc($link['title']) ?>"
<?= $link['attrs'] ?? '' ?>>
<span class="role-nav-icon">
<i class="bi <?= esc($link['icon']) ?>"></i>
</span>
<span class="role-nav-label"><?= esc($link['label']) ?></span>
<?php if (!empty($badge)): ?>
<span class="role-nav-badge"><?= esc($badge) ?></span>
<?php endif; ?>
</a>
<?php endforeach; ?>
</div>
<?php elseif (($role === 'teacher') || ($role === 'teacher_assistant')): ?>
<?php
$teacherLinks = [
[
'href' => $dashboard,
'icon' => 'bi-house-door',
'label' => 'Dashboard',
'title' => 'View notices, summary stats and recent updates.',
],
[
'href' => base_url('/teacher/class_view'),
'icon' => 'bi-pencil-square',
'label' => 'Class',
'title' => 'Manage your assigned class list.',
],
[
'href' => base_url('/teacher/showupdate_attendance?class_section_id=' . ($class_section_id ?? '')),
'icon' => 'bi-calendar-check',
'label' => 'Attendance',
'title' => 'Update student attendance records.',
],
[
'href' => base_url('/teacher/absence'),
'icon' => 'bi-megaphone',
'label' => 'TimeOff',
'title' => 'Report your absence or vacation days.',
],
[
'href' => base_url('teacher/print-requests'),
'icon' => 'bi-printer',
'label' => 'Print',
'title' => 'Submit and track print/copy requests.',
],
[
'href' => base_url('teacher/progress/submit'),
'icon' => 'bi-clipboard-check',
'label' => 'Class Progress',
'title' => 'Submit weekly class progress.',
],
[
'href' => base_url('/teacher/scores'),
'icon' => 'bi-clipboard-data',
'label' => 'Scores',
'title' => 'Input, view and update student scores.',
],
[
'href' => base_url('/teacher/competition-scores'),
'icon' => 'bi-trophy',
'label' => 'Competitions',
'title' => 'Enter competition scores for your class.',
],
[
'href' => base_url('/teacher/exam-drafts'),
'icon' => 'bi-file-earmark-text',
'label' => 'Exam Drafts',
'title' => 'Submit or review draft exams that need administrator approval.',
],
[
'href' => base_url('inventory/books/distribute'),
'icon' => 'bi-book',
'label' => 'Books',
'title' => 'Review and distribute books.',
],
[
'href' => base_url('/teacher/calendar'),
'icon' => 'bi-calendar-day',
'label' => 'Calendar',
'title' => 'View school-wide calendar of classes, events, and holidays.',
],
];
if ($scoreCardEnabledRole) {
$teacherLinks[] = [
'href' => base_url('student/score-card/list'),
'icon' => 'bi-card-list',
'label' => 'Score Card',
'title' => 'Open a student score card.',
];
}
usort($teacherLinks, static function ($a, $b) {
$la = strtolower((string)($a['label'] ?? ''));
$lb = strtolower((string)($b['label'] ?? ''));
if ($la === 'dashboard' && $lb !== 'dashboard') return -1;
if ($lb === 'dashboard' && $la !== 'dashboard') return 1;
return strcasecmp($la, $lb);
});
?>
<div class="role-nav-grid">
<?php foreach ($teacherLinks as $link): ?>
<a href="<?= esc($link['href']) ?>"
class="nav-item nav-link role-nav-link"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="<?= esc($link['title']) ?>"
<?= $link['attrs'] ?? '' ?>>
<span class="role-nav-icon">
<i class="bi <?= esc($link['icon']) ?>"></i>
</span>
<span class="role-nav-label"><?= esc($link['label']) ?></span>
</a>
<?php endforeach; ?>
</div>
<?php elseif ($role === 'student' || $role === 'guest'): ?>
<span class="nav-link text-warning">Please contact administration to assign a role to your account.</span>
<?php endif; ?>
</div>
<?php
// Role switcher + style combined under one "Quick Menu"
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
$current = strtolower((string) (session()->get('role') ?? 'guest'));
$other = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $current));
$styleCfg = config('Style');
$sess = session();
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
?>
<div class="nav-item dropdown ms-lg-3">
<div class="dropdown-menu dropdown-menu-end quick-menu" aria-labelledby="quickMenu" style="max-height: 70vh; overflow-y: auto; overflow-x: hidden;">
<?php if (!empty($other)): ?>
<h6 class="dropdown-header">Switch Role</h6>
<?php foreach ($other as $r): ?>
<form method="post" action="<?= base_url('set-role') ?>" class="px-2">
<?= csrf_field() ?>
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
</form>
<?php endforeach; ?>
<div class="dropdown-divider"></div>
<?php endif; ?>
<h6 class="dropdown-header">Style</h6>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddAccentQuick" role="button" aria-expanded="true" aria-controls="ddAccentQuick">
Accent <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse show" id="ddAccentQuick">
<div class="px-2 pb-2">
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentAccent); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?accent=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<div class="px-2 small text-muted">Menu</div>
<?php foreach (array_keys($styleCfg->menuPalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentMenu); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?menu=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</div>
</div>
<!-- Avatar dropdown outside collapse to avoid clipping and keep right spacing -->
<?php
// Role switcher + style selections (ensure vars exist out here)
if (!isset($other) || !isset($styleCfg) || !isset($currentAccent) || !isset($currentMenu)) {
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
$current = strtolower((string) (session()->get('role') ?? 'guest'));
$other = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $current));
$styleCfg = config('Style');
$sess = session();
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
}
?>
<ul class="navbar-nav ms-auto me-4">
<li class="nav-item dropdown">
<a class="nav-link p-0" href="#" id="quickMenu" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" aria-label="Open user menu">
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center" style="width: 40px; height: 40px; background-color: var(--app-primary);">
<?= esc($initials) ?>
</div>
</a>
<div class="dropdown-menu dropdown-menu-end quick-menu" aria-labelledby="quickMenu" style="max-height: 70vh; overflow-y: auto; overflow-x: hidden; min-width: 260px; max-width: min(320px, calc(100vw - 16px)); right: 8px; left: auto;">
<div class="px-3 py-3 d-flex align-items-center">
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center me-3" style="width: 36px; height: 36px; background-color: var(--app-primary);">
<?= esc($initials) ?>
</div>
<div>
<div class="fw-semibold mb-0" style="line-height: 1.2;"><?= esc($userName !== '' ? $userName : 'User') ?></div>
<div class="text-muted small" style="line-height: 1.2;"><?= esc($role) ?><?= $userEmail ? ' · ' . esc($userEmail) : '' ?></div>
</div>
</div>
<div class="dropdown-divider"></div>
<?php if (!empty($other)): ?>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddRoleBodyLP" role="button" aria-expanded="false" aria-controls="ddRoleBodyLP">
Switch Role <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse" id="ddRoleBodyLP">
<div class="px-2 pb-2">
<?php foreach ($other as $r): ?>
<form method="post" action="<?= base_url('set-role') ?>" class="mb-1">
<?= csrf_field() ?>
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
</form>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<?php endif; ?>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddStyleBodyLP" role="button" aria-expanded="false" aria-controls="ddStyleBodyLP">
Style <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse" id="ddStyleBodyLP">
<div class="px-2 pb-2">
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddAccentAvatar" role="button" aria-expanded="true" aria-controls="ddAccentAvatar">
Accent <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse show" id="ddAccentAvatar">
<div class="px-2 pb-2">
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentAccent); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?accent=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current=\"true\"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<div class="px-2 small text-muted">Menu</div>
<div class="px-2 pb-2">
<div class="table-responsive">
<table class="table table-borderless mb-2" style="min-width:auto;">
<tbody>
<?php
$palettes = $styleCfg->menuPalettes ?? [];
$keys = array_keys($palettes);
$cols = 3; $i = 0;
foreach ($keys as $k):
if ($i % $cols === 0) echo '<tr>';
$pal = $palettes[$k];
$bg = (string)($pal['bg'] ?? '#fff');
$tx = (string)($pal['text'] ?? '#000');
$active = ($k === $currentMenu) ? 'outline-success' : 'outline-secondary';
?>
<td class="p-1" style="width:33.33%;">
<a href="<?= site_url('ui/style?menu=' . urlencode($k) . '&back=' . urlencode(current_url())) ?>" class="btn btn-<?= $active ?> w-100" style="padding:6px;">
<div class="rounded" style="height:28px; background-color: <?= esc($bg) ?>; color: <?= esc($tx) ?>; display:flex; align-items:center; justify-content:center; font-size:.8rem;">
<?= ucfirst(esc($k)) ?>
</div>
</a>
</td>
<?php
$i++;
if ($i % $cols === 0) echo '</tr>';
endforeach;
if ($i % $cols !== 0) { while ($i % $cols !== 0) { echo '<td class="p-1"></td>'; $i++; } echo '</tr>'; }
?>
</tbody>
</table>
</div>
<!-- Custom color picker -->
<form action="<?= site_url('ui/style') ?>" method="get" class="px-1">
<input type="hidden" name="menu" value="custom">
<input type="hidden" name="back" value="<?= esc(current_url()) ?>">
<div class="row g-2 align-items-center">
<div class="col-6">
<label class="form-label mb-1 small">Menu BG</label>
<input type="color" name="menu_bg" value="<?= esc($menuLP['bg'] ?? '#0f172a') ?>" class="form-control form-control-color w-100" title="Pick background color">
</div>
<div class="col-6">
<label class="form-label mb-1 small">Text</label>
<input type="color" name="menu_text" value="<?= esc($menuLP['text'] ?? '#ffffff') ?>" class="form-control form-control-color w-100" title="Pick text color">
</div>
<div class="col-12">
<label class="form-label mb-1 small">Mode</label>
<div>
<?php $modeLP = ($menuLP['mode'] ?? 'light'); ?>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mm_light" value="light" <?= $modeLP==='light'?'checked':'' ?>>
<label class="form-check-label" for="mm_light">Light</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mm_dark" value="dark" <?= $modeLP==='dark'?'checked':'' ?>>
<label class="form-check-label" for="mm_dark">Dark</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="menu_mode" id="mm_auto" value="auto" <?= ($modeLP!=='light' && $modeLP!=='dark')?'checked':'' ?>>
<label class="form-check-label" for="mm_auto">Auto</label>
</div>
</div>
</div>
<div class="col-12 mt-1">
<button type="submit" class="btn btn-sm btn-primary w-100">Apply Custom</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="<?= base_url('/logout') ?>">Log Out</a>
</div>
</li>
</ul>
</nav>
+420
View File
@@ -0,0 +1,420 @@
<?php
// Get and normalize the role
$role = strtolower(session()->get('role') ?? 'guest');
?>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<!-- Administrator Menus -->
<?php if ($role === 'administrator'): ?>
<!-- User Management -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="userManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Users
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="<?= base_url('notifications/active') ?>">Active Notifications</a>
<a class="dropdown-item" href="<?= base_url('notifications/deleted') ?>">Deleted Notifications</a>
<a class="dropdown-item" href="/user/login_activity">Login Activity</a>
<a class="dropdown-item" href="/user/user_list">User List</a>
</div>
</li>
<!-- Roles -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="roleManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Roles
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/rolepermission/assign_role">Assign User Role</a>
<a class="dropdown-item" href="/rolepermission/roles">Role Management</a>
</div>
</li>
<!-- Configuration -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="configManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Configuration
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/configuration/configuration_view">Add/Edit Configuration</a>
</div>
</li>
<!-- Staff Management Dropdown -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="parentsManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Staffing
</a>
<div class="dropdown-menu" aria-labelledby="parentsManagementDropdown">
<a class="dropdown-item" href="/staff/index">Staff Profile</a>
<a class="dropdown-item" href="/administrator/teacher_class_assignment">Teacher Class Assignment</a>
</div>
</li>
<!-- Parents Management Dropdown -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="parentsManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Parents
</a>
<div class="dropdown-menu" aria-labelledby="parentsManagementDropdown">
<a class="dropdown-item" href="/administrator/parent_profiles">Parent Profile</a>
</div>
</li>
<!-- Students -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="studentManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Student-Affairs
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/administrator/daily_attendance">Attendance Management</a>
<a class="dropdown-item" href="<?= base_url('attendance/violations') ?>">Attendance Tracking System</a>
<a class="dropdown-item" href="/rfid_coming_soon">Attendance Scans</a>
<a class="dropdown-item" href="/administrator/class_assignment">Classes List</a>
<a class="dropdown-item" href="/administrator/emergency_contact">Emergency Contact</a>
<a class="dropdown-item" href="/enroll_withdraw/enrollment_withdrawal">Enrollment-Withdrawal</a>
<!--a class="dropdown-item" href="/administrator/exam_management">Exams Management</a-->
<a class="dropdown-item" href="/flags/flags_management">Flags Management</a>
<a class="dropdown-item" href="/administrator/calendar_view">School Calendar</a>
<a class="dropdown-item" href="/report/combined">Score Analysis</a>
<a class="dropdown-item" href="/grading">Score Management</a>
<a class="dropdown-item" href="/administrator/student_class_assignment">Student Class Assignment</a>
<a class="dropdown-item" href="/administrator/student_profiles">Student Profile</a>
</div>
</li>
<!-- Classes -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="classesManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Classes
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/administrator/class_assignment">Classes List</a>
<a class="dropdown-item" href="/administrator/subject-curriculum">Subject Curriculum</a>
</div>
</li>
<!-- Communication -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="communicationToolsDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Communication
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/emails/parent_email_extractor">Parent Email Extractor</a>
<a class="dropdown-item" href="/administrator/parent_profiles">Parent Profile</a>
<a class="dropdown-item" href="/administrator/student_profiles">Student Profile</a>
</div>
</li>
<!-- Financial -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="financialManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Financial
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/discounts/list">Discount Management</a>
<a class="dropdown-item" href="/expenses/index">Expenses Management</a>
<a class="dropdown-item" href="/payment/financial_report">Financial Report</a>
<a class="dropdown-item" href="/invoice_payment/invoice_management">Invoices Management</a>
<a class="dropdown-item" href="/payment/manual_pay">Manual Payment</a>
<a class="dropdown-item" href="/administrator/paypal_transactions">PaypalTransactions</a>
<a class="dropdown-item" href="/refunds/list">Refund Management</a>
<a class="dropdown-item" href="/reimbursements/index">Reimbursement Management</a>
<a class="dropdown-item" href="/payment/notification_management">Payment Notification Management</a>
</div>
</li>
<!-- Analytics -->
<li class="nav-item dropdown">
<!--a class="nav-link dropdown-toggle" href="#" id="reportsAnalyticsDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Analytics
</a-->
<div class="dropdown-menu">
<!-- Placeholder -->
</div>
</li>
<!-- Printables -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="printablesReportsDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Printables
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/printables_reports/badge_form">Badges</a>
<a class="dropdown-item" href="<?= site_url('class-prep') ?>">Class Prep</a>
<!--a class="dropdown-item" href="/printables_reports/certificates">Certificates</a-->
<a class="dropdown-item" href="/printables_reports/report_card">Report Cards</a>
<a class="dropdown-item" href="/printables_reports/stickers">Stickers</a>
</div>
</li>
<!-- Extra -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="extracurricularActivitiesDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Event Management
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="<?= site_url('administrator/calendar') ?>"> Calendar</a>
<a class="dropdown-item" href="<?= site_url('administrator/events') ?>">Events</a>
</div>
</li>
<!-- Principal -->
<?php elseif ($role === 'principal' || $role === 'vice_principal'): ?>
<!-- Staff Management Dropdown -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="parentsManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Staffing
</a>
<div class="dropdown-menu" aria-labelledby="parentsManagementDropdown">
<a class="dropdown-item" href="/staff/index">Staff Profile</a>
<a class="dropdown-item" href="/administrator/teacher_class_assignment">Teacher Class Assignment</a>
</div>
</li>
<!-- Parents Management Dropdown -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="parentsManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Parents
</a>
<div class="dropdown-menu" aria-labelledby="parentsManagementDropdown">
<a class="dropdown-item" href="/administrator/parent_profiles">Parent Profile</a>
</div>
</li>
<!-- Students -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="studentManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Student-Affairs
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/administrator/daily_attendance">Attendance Management</a>
<!--a class="dropdown-item" href="/rfid_coming_soon">Attendance Scans</a-->
<a class="dropdown-item" href="/administrator/class_assignment">Classes List</a>
<a class="dropdown-item" href="/administrator/emergency_contact">Emergency Contact</a>
<a class="dropdown-item" href="/enroll_withdraw/enrollment_withdrawal">Enrollment-Withdrawal</a>
<!--a class="dropdown-item" href="/administrator/exam_management">Exams Management</a-->
<a class="dropdown-item" href="/flags/flags_management">Flags Management</a>
<a class="dropdown-item" href="/administrator/calendar_view">School Calendar</a>
<a class="dropdown-item" href="/report/combined">Score Analysis</a>
<a class="dropdown-item" href="/grading">Score Management</a>
<a class="dropdown-item" href="/administrator/student_class_assignment">Student Class Assignment</a>
<a class="dropdown-item" href="/administrator/student_profiles">Student Profile</a>
</div>
</li>
<!-- Financial -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="financialManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Financial
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/discounts/list">Discount Management</a>
<a class="dropdown-item" href="/expenses/index">Expenses Management</a>
<a class="dropdown-item" href="/payment/financial_report">Financial Report</a>
<a class="dropdown-item" href="/invoice_payment/invoice_management">Invoices Management</a>
<a class="dropdown-item" href="/payment/manual_pay">Manual Payment</a>
<a class="dropdown-item" href="/administrator/paypal_transactions">PaypalTransactions</a>
<a class="dropdown-item" href="/refunds/list">Refund Management</a>
<a class="dropdown-item" href="/reimbursements/index">Reimbursement Management</a>
</div>
</li>
<!-- Printables -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="printablesReportsDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Printables
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/printables_reports/badge_form">Badges</a>
<a class="dropdown-item" href="<?= site_url('class-prep') ?>">Class Prep</a>
<!--a class="dropdown-item" href="/printables_reports/certificates">Certificates</a-->
<a class="dropdown-item" href="/printables_reports/report_card">Report Cards</a>
<!--a class="dropdown-item" href="/printables_reports/stickers">Stickers</a-->
</div>
</li>
<!-- Extra -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="extracurricularActivitiesDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Event Management
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="<?= site_url('administrator/events') ?>">Events</a>
</div>
</li>
<!--admin-->
<?php elseif ($role === 'admin'): ?>
<li class="nav-item"><a class="nav-link" href="/enroll_withdraw/enrollment_withdrawal">Enrollment</a></li>
<li class="nav-item"><a class="nav-link" href="/invoice_payment/invoice_management">Invoice Management</a></li>
<!--head of department (communication)-->
<?php elseif ($role === 'head of department (communication)'): ?>
<!-- Communication -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="communicationToolsDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Communication
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/administrator/parent_profiles">Parent Profile</a>
<a class="dropdown-item" href="/administrator/student_profiles">Student Profile</a>
</div>
</li>
<!--head of department (information technology-->
<?php elseif ($role === 'head of department (information technology)'): ?>
<li class="nav-item"><a class="nav-link" href="/grading">IT Dept Grades</a></li>
<!--head of department (education)-->
<?php elseif ($role === 'head of department (education)'): ?>
<!-- Students -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="studentManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Student-Affairs
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/administrator/daily_attendance">Attendance Management</a>
<!--a class="dropdown-item" href="/rfid_coming_soon">Attendance Scans</a-->
<a class="dropdown-item" href="/administrator/class_assignment">Classes List</a>
<a class="dropdown-item" href="/administrator/emergency_contact">Emergency Contact</a>
<a class="dropdown-item" href="/enroll_withdraw/enrollment_withdrawal">Enrollment-Withdrawal</a>
<!--a class="dropdown-item" href="/administrator/exam_management">Exams Management</a-->
<a class="dropdown-item" href="/flags/flags_management">Flags Management</a>
<a class="dropdown-item" href="/administrator/calendar_view">School Calendar</a>
<a class="dropdown-item" href="/report/combined">Score Analysis</a>
<a class="dropdown-item" href="/grading">Score Management</a>
<a class="dropdown-item" href="/administrator/student_class_assignment">Student Class Assignment</a>
<a class="dropdown-item" href="/administrator/student_profiles">Student Profile</a>
</div>
</li>
<!--head of department (finance)-->
<?php elseif ($role === 'head of department (finance)'): ?>
<!-- Financial -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="financialManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Financial
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/expenses/index">Expenses Management</a>
<a class="dropdown-item" href="/payment/financial_report">Financial Report</a>
<a class="dropdown-item" href="/invoice_payment/invoice_management">Invoices Management</a>
<a class="dropdown-item" href="/payment/manual_pay">Manual Payment</a>
<a class="dropdown-item" href="/administrator/paypal_transactions">PaypalTransactions</a>
<a class="dropdown-item" href="/refunds/list">Refund Management</a>
<a class="dropdown-item" href="/reimbursements/index">Reimbursement Management</a>
</div>
</li>
<?php endif; ?>
<?php
// Back office: combine role switch + style under one dropdown
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
$current = strtolower((string) (session()->get('role') ?? 'guest'));
$other = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $current));
$styleCfg = config('Style');
$sess = session();
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
?>
<li class="nav-item dropdown">
<div class="dropdown-menu dropdown-menu-end quick-menu" aria-labelledby="quickMenuBack" style="max-height: 70vh; overflow-y: auto; overflow-x: hidden;">
<?php if (!empty($other)): ?>
<h6 class="dropdown-header">Switch Role</h6>
<?php foreach ($other as $r): ?>
<form method="post" action="<?= base_url('set-role') ?>" class="px-2">
<?= csrf_field() ?>
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
</form>
<?php endforeach; ?>
<div class="dropdown-divider"></div>
<?php endif; ?>
<h6 class="dropdown-header">Style</h6>
<div class="px-2 small text-muted">Accent</div>
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentAccent); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?accent=' . urlencode($opt)) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
<div class="dropdown-divider"></div>
<div class="px-2 small text-muted">Menu</div>
<?php foreach (array_keys($styleCfg->menuPalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentMenu); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?menu=' . urlencode($opt)) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</li>
<div class="d-flex">
<button class="btn btn-outline-light logout-btn ms-lg-3" onclick="window.location.href='<?= base_url('/logout'); ?>'">
Log Out
</button>
</div>
</ul>
</div>
</nav>
<!-- Admins Management Dropdown -->
<!--li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="adminsManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Admins
</a>
<div class="dropdown-menu" aria-labelledby="adminsManagementDropdown">
<Additional admin management options can be added here
>
</div>
</li-->
<!-- Teacher Management Dropdown -->
<!--li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="teacherManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Teachers
</a>
<div class="dropdown-menu" aria-labelledby="teacherManagementDropdown">
< Add teacher management options here >
</div>
</li-->
<!-- Parents Management Dropdown -->
<!--li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="parentsManagementDropdown" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Parents
</a>
<div class="dropdown-menu" aria-labelledby="parentsManagementDropdown">
< Add parents management options here >
</div>
</li-->
+441
View File
@@ -0,0 +1,441 @@
<?php
/** @var array $rolesFromSession */
use App\Services\NavbarService;
$rolesFromSession = [];
$rawRole = session()->get('role'); // your app uses a single role string
if (is_array($rawRole)) $rolesFromSession = $rawRole;
else $rolesFromSession = [$rawRole ?? 'guest'];
$service = new NavbarService();
$menu = $service->getMenuForRoles($rolesFromSession);
function nav_url(string $path): string
{
$path = trim($path);
if ($path === '' || preg_match('/[<>]/', $path)) {
return '#';
}
// Treat relative paths as site_url, absolute keep as is.
if (preg_match('#^https?://#i', $path)) return $path;
return site_url($path);
}
?>
<style>
/* Mobile-friendly sidebar behavior and backdrop */
@media (max-width: 991.98px) {
#navbarManagement.mgmt-sidebar { width: min(88vw, 360px); transform: translateX(-100%); will-change: transform; }
html.mgmt-sidebar-open #navbarManagement.mgmt-sidebar { transform: translateX(0); }
#mgmtSidebarHotzone { display: none !important; }
.mgmt-sidebar-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.35); z-index: 1043; display: none; }
html.mgmt-sidebar-open .mgmt-sidebar-backdrop { display: block; }
body.mgmt-no-scroll { overflow: hidden; touch-action: none; }
#navbarManagement.mgmt-sidebar .dropdown-menu { display: none !important; }
}
@media (min-width: 992px) { .mgmt-sidebar-backdrop { display: none !important; } }
#navbarManagement .submenu .nav-link, #navbarManagement .mobile-submenu .nav-link { padding: .4rem .5rem; }
#navbarManagement .submenu .dropdown-header, #navbarManagement .mobile-submenu .dropdown-header { padding: .35rem .5rem; }
#navbarManagement .submenu-toggle, #navbarManagement .mobile-toggle { width: 100%; text-align: left; }
/* Arrow toggle styling follow page style */
.mgmt-sidebar-toggle {
position: fixed;
left: 10px;
top: 72px; /* JS nudges based on header height */
width: 34px;
height: 34px;
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
border-radius: 9999px;
background-color: var(--mgmt-primary);
color: #fff;
box-shadow: 0 2px 6px rgba(0,0,0,0.25);
z-index: 1060; /* above sidebar */
cursor: pointer;
transition: transform .2s ease, background-color .2s ease, opacity .2s ease;
}
.mgmt-sidebar-toggle:hover { background-color: var(--mgmt-primary-hover); }
html.mgmt-sidebar-open .mgmt-sidebar-toggle i { transform: rotate(180deg); }
/* Rotate submenu chevron when expanded */
#navbarManagement .submenu-toggle[aria-expanded="true"] i { transform: rotate(180deg); }
</style>
<button id="mgmtSidebarToggle" class="mgmt-sidebar-toggle" aria-label="Toggle sidebar" aria-expanded="false">
<i class="bi bi-chevron-right"></i>
</button>
<nav id="navbarManagement" class="mgmt-sidebar">
<div class="mgmt-sidebar-content">
<ul class="nav flex-column" id="mgmtMenuList">
<?php foreach ($menu as $item): ?>
<?php $hasChildren = !empty($item['children']); ?>
<?php if ($hasChildren): ?>
<li class="nav-item dropdown dropend d-none">
<a class="nav-link d-flex align-items-center justify-content-between dropdown-toggle" href="#" id="dd_<?= esc($item['id']) ?>" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" data-bs-display="static" aria-expanded="false">
<span class="nav-label-chip flex-shrink-0"><?= esc($item['label']) ?></span>
<i class="bi bi-chevron-right ms-2"></i>
</a>
<div class="dropdown-menu shadow sidebar-dropdown-menu" aria-labelledby="dd_<?= esc($item['id']) ?>">
<?php foreach ($item['children'] as $child): ?>
<?php if ($child['url']): ?>
<a class="dropdown-item" href="<?= esc(nav_url($child['url']), 'attr') ?>" <?= $child['target'] ? 'target="' . esc($child['target']) . '"' : '' ?>>
<?= esc($child['label']) ?>
</a>
<?php else: ?>
<h6 class="dropdown-header mb-1"><?= esc($child['label']) ?></h6>
<?php endif; ?>
<?php endforeach; ?>
</div>
</li>
<?php $cid = 'mnav_'.esc($item['id']); ?>
<li class="nav-item d-block">
<button class="nav-link d-flex align-items-center justify-content-between mobile-toggle submenu-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#<?= $cid ?>" aria-controls="<?= $cid ?>" aria-expanded="false">
<span class="nav-label-chip flex-shrink-0"><?= esc($item['label']) ?></span>
<i class="bi bi-chevron-down ms-2"></i>
</button>
<div id="<?= $cid ?>" class="collapse submenu" data-bs-parent="#mgmtMenuList">
<ul class="nav flex-column ms-2">
<?php foreach ($item['children'] as $child): ?>
<?php if ($child['url']): ?>
<li class="nav-item"><a class="nav-link" href="<?= esc(nav_url($child['url']), 'attr') ?>" <?= $child['target'] ? 'target="' . esc($child['target']) . '"' : '' ?>><?= esc($child['label']) ?></a></li>
<?php else: ?>
<li class="nav-item"><span class="dropdown-header mb-1 text-muted small"><?= esc($child['label']) ?></span></li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
</div>
</li>
<?php else: ?>
<li class="nav-item">
<?php if (!empty($item['url'])): ?>
<a class="nav-link d-flex align-items-center" href="<?= esc(nav_url($item['url']), 'attr') ?>" <?= $item['target'] ? 'target="' . esc($item['target']) . '"' : '' ?>>
<span class="nav-label-chip flex-shrink-0"><?= esc($item['label']) ?></span>
</a>
<?php else: ?>
<span class="nav-link disabled d-flex align-items-center">
<span class="nav-label-chip flex-shrink-0"><?= esc($item['label']) ?></span>
</span>
<?php endif; ?>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<div class="d-flex align-items-center">
<?php
// Build role switcher options when user has multiple roles
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
$currentRole = strtolower((string) ($rawRole ?? 'guest'));
$otherRoles = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $currentRole));
// Style settings (with sensible defaults)
$styleCfg = config('Style');
$sess = session();
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
?>
<div class="nav-item dropdown me-2">
<div class="dropdown-menu dropdown-menu-end quick-menu" aria-labelledby="dd_tools" style="max-height: 70vh; overflow-y: auto; overflow-x: hidden;">
<?php if (!empty($otherRoles)): ?>
<h6 class="dropdown-header">Switch Role</h6>
<?php foreach ($otherRoles as $r): ?>
<form method="post" action="<?= site_url('set-role') ?>">
<?= csrf_field() ?>
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
</form>
<?php endforeach; ?>
<div class="dropdown-divider"></div>
<?php endif; ?>
<h6 class="dropdown-header">Style</h6>
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddAccentMgmtSidebar" role="button" aria-expanded="true" aria-controls="ddAccentMgmtSidebar">
Accent <i class="bi bi-chevron-down ms-2"></i>
</a>
<div class="collapse show" id="ddAccentMgmtSidebar">
<div class="px-2 pb-2">
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentAccent); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" data-style-link href="<?= site_url('ui/style?accent=' . urlencode($opt)) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</div>
<div class="dropdown-divider"></div>
<div class="px-2 small text-muted">Menu</div>
<?php foreach (array_keys($styleCfg->menuPalettes ?? []) as $opt): ?>
<?php $isActive = ($opt === $currentMenu); ?>
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" data-style-link href="<?= site_url('ui/style?menu=' . urlencode($opt)) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
</a>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
</nav>
<div id="mgmtSidebarHotzone" aria-hidden="true"></div>
<div id="mgmtSidebarBackdrop" class="mgmt-sidebar-backdrop" aria-hidden="true"></div>
<script>
(function() {
function applySidebarGeometry() {
const header = document.querySelector('header.navbar.sticky-top, header.navbar.fixed-top') || document.querySelector('header.navbar');
const nav = document.getElementById('navbarManagement');
const hot = document.getElementById('mgmtSidebarHotzone');
const toggle = document.getElementById('mgmtSidebarToggle');
if (!nav) return;
let top = 0;
if (header) {
top = Math.max(header.offsetHeight || 0, (header.getBoundingClientRect && header.getBoundingClientRect().height) || 0);
}
nav.style.top = top + 'px';
nav.style.height = 'calc(100vh - ' + top + 'px)';
// Keep sidebar above backdrop (1043) but below header (1045)
nav.style.zIndex = 1044;
if (hot) {
hot.style.top = top + 'px';
hot.style.height = 'calc(100vh - ' + top + 'px)';
hot.style.zIndex = 1019;
}
if (toggle) { try { toggle.style.top = (top + 12) + 'px'; } catch(_) {} }
}
window.addEventListener('load', applySidebarGeometry);
window.addEventListener('resize', applySidebarGeometry);
document.addEventListener('DOMContentLoaded', applySidebarGeometry);
})();
</script>
<script>
// Toggle sidebar open/close (button + backdrop) and lock body scroll on mobile
(function() {
var root = document.documentElement;
var btn = document.getElementById('mgmtSidebarToggle');
var backdrop = document.getElementById('mgmtSidebarBackdrop');
if (!btn) return;
function setExpanded(expanded) {
try { btn.setAttribute('aria-expanded', expanded ? 'true' : 'false'); } catch (_) {}
try { document.body.classList.toggle('mgmt-no-scroll', expanded && !window.matchMedia('(min-width: 992px)').matches); } catch (_) {}
}
function closeSidebar() {
root.classList.remove('mgmt-sidebar-open');
setExpanded(false);
}
btn.addEventListener('click', function(e) {
e.stopPropagation();
var willOpen = !root.classList.contains('mgmt-sidebar-open');
root.classList.toggle('mgmt-sidebar-open');
setExpanded(willOpen);
});
if (backdrop) backdrop.addEventListener('click', function() { closeSidebar(); });
document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeSidebar(); });
document.addEventListener('click', function(e) {
if (!root.classList.contains('mgmt-sidebar-open')) return;
if (e.target.closest('#navbarManagement') || e.target.closest('#mgmtSidebarToggle')) return;
closeSidebar();
});
// Desktop: hover the arrow to reveal the sidebar (large screens only)
// Use width-only gating to be robust across devices that misreport pointer/hover
if (window.matchMedia('(min-width: 992px)').matches) {
btn.addEventListener('mouseenter', function() {
root.classList.add('mgmt-sidebar-open');
setExpanded(true);
});
btn.addEventListener('mouseleave', function() {
setTimeout(function() {
var navHover = document.querySelector('#navbarManagement:hover');
var btnHover = document.querySelector('#mgmtSidebarToggle:hover');
if (!navHover && !btnHover) closeSidebar();
}, 600);
});
}
})();
</script>
<script>
// Ensure style links return to the current page
(function() {
document.addEventListener('click', function(e) {
var a = e.target.closest('a[data-style-link]');
if (!a) return;
try {
var u = new URL(a.getAttribute('href'), window.location.origin);
if (!u.searchParams.get('back')) {
u.searchParams.set('back', window.location.href);
}
e.preventDefault();
window.location.assign(u.toString());
} catch (_) {
/* ignore */ }
});
})();
</script>
<script>
// Hover-to-open behavior with a thin hotzone at the left edge (desktop only)
(function() {
if (!window.matchMedia('(hover: hover) and (pointer: fine) and (min-width: 992px)').matches) return;
var root = document.documentElement;
var nav = document.getElementById('navbarManagement');
var hot = document.getElementById('mgmtSidebarHotzone');
if (!nav || !hot) return;
var closing;
var CLOSE_DELAY = 600; // allow time to move into flyout
function open() {
root.classList.add('mgmt-sidebar-open');
}
function scheduleClose() {
if (closing) clearTimeout(closing);
closing = setTimeout(function() {
root.classList.remove('mgmt-sidebar-open');
}, CLOSE_DELAY);
}
function cancelClose() {
if (closing) {
clearTimeout(closing);
closing = null;
}
}
hot.addEventListener('mouseenter', function() {
cancelClose();
open();
});
hot.addEventListener('mouseleave', function() {
scheduleClose();
});
nav.addEventListener('mouseenter', function() {
cancelClose();
open();
});
nav.addEventListener('mouseleave', function() {
scheduleClose();
});
/* touch behavior disabled; mobile uses visible toggle */
// ESC closes
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
scheduleClose();
}
});
// Keep open while interacting with dropdown flyouts
nav.addEventListener('shown.bs.dropdown', function() {
cancelClose();
open();
}, true);
nav.addEventListener('hide.bs.dropdown', function() {
scheduleClose();
}, true);
nav.addEventListener('mouseenter', function(e) {
if (e.target && e.target.classList && e.target.classList.contains('dropdown-menu')) {
cancelClose();
}
}, true);
nav.addEventListener('mouseleave', function(e) {
if (e.target && e.target.classList && e.target.classList.contains('dropdown-menu')) {
scheduleClose();
}
}, true);
// Expose helpers for other scripts
try {
window._mgmtSidebarKeepOpen = {
open: open,
scheduleClose: scheduleClose,
cancelClose: cancelClose
};
} catch (_) {}
})();
</script>
<script>
// Simple click-open guard so the sidebar is open before dropdown shows (desktop only)
(function() {
if (!window.matchMedia('(min-width: 992px)').matches) return;
var nav = document.getElementById('navbarManagement');
if (!nav) return;
nav.addEventListener('click', function(e) {
var t = e.target.closest('.dropdown-toggle');
if (!t || !nav.contains(t)) return;
var root = document.documentElement;
if (!root.classList.contains('mgmt-sidebar-open')) {
e.preventDefault();
e.stopPropagation();
root.classList.add('mgmt-sidebar-open');
setTimeout(function() {
try {
new bootstrap.Dropdown(t).show();
} catch (_) {
try {
t.click();
} catch (__) {}
}
}, 180);
}
}, true);
})();
</script>
<!-- Desktop dropdowns: robust open/close without body portal -->
<script>
(function() {
if (!window.matchMedia('(min-width: 992px)').matches) return;
var nav = document.getElementById('navbarManagement');
if (!nav) return;
function findMenu(t) {
if (!t) return null;
var id = t.id;
if (id) {
var menuById = nav.querySelector('.dropdown-menu[aria-labelledby="' + id + '"]');
if (menuById) return menuById;
}
try { return t.parentElement.querySelector(':scope > .dropdown-menu'); } catch (_) { return t.parentElement.querySelector('.dropdown-menu'); }
}
function hideAll() {
nav.querySelectorAll('.nav-item.dropend .dropdown-menu.show').forEach(function(m){ m.classList.remove('show'); m.style.visibility=''; m.style.opacity=''; });
nav.querySelectorAll('.nav-item.dropend .dropdown-toggle[aria-expanded="true"]').forEach(function(t){ t.setAttribute('aria-expanded','false'); });
}
function showDropend(t) {
var menu = findMenu(t);
if (!menu) return;
try {
new bootstrap.Dropdown(t, { autoClose: 'outside' }).show();
} catch (_) {
// Fallback without Bootstrap
t.setAttribute('aria-expanded','true');
menu.classList.add('show');
}
}
// Toggle dropdowns on click (prevent duplicate toggles)
nav.addEventListener('click', function(e) {
var t = e.target.closest('.nav-item.dropend > .dropdown-toggle');
if (!t) return;
e.preventDefault();
e.stopPropagation();
var menu = findMenu(t);
var isOpen = !!(menu && menu.classList.contains('show'));
hideAll();
if (!isOpen) showDropend(t);
}, true);
// Close when clicking outside the management sidebar
document.addEventListener('click', function(e) {
if (!e.target.closest('#navbarManagement')) hideAll();
}, true);
// Close on ESC
document.addEventListener('keydown', function(e) { if (e.key === 'Escape') hideAll(); });
})();
</script>
+43
View File
@@ -0,0 +1,43 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<div class="container mt-5">
<!-- Show the modal only if there's an error message -->
<?php if (session()->getFlashdata('error')): ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Show the modal
var errorModal = new bootstrap.Modal(document.getElementById('errorModal'), {
keyboard: false, // Disable closing on ESC key
backdrop: 'static' // Prevent closing when clicking outside the modal
});
errorModal.show(); // Show the modal when the page loads
// Reload the page after 5 seconds
setTimeout(function() {
location.reload(); // Refresh the page
}, 50); // 5000 milliseconds = 5 seconds
});
</script>
<?php endif; ?>
<!-- Error Modal -->
<div class="modal fade" id="errorModal" tabindex="-1" aria-labelledby="errorModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="errorModalLabel">Error</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
+67
View File
@@ -0,0 +1,67 @@
<!-- sidebar.php -->
<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="/parent_dashboard">
<i class="bi bi-house-door"></i>
Dashboard
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('parent/register_kid_form'); ?>">
<i class="bi bi-person-plus"></i>
Register Kids
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('parent/enroll_classes'); ?>">
<i class="bi bi-pencil-square"></i>
Enroll in Classes
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('parent/attendance'); ?>">
<i class="bi bi-calendar-check"></i>
Attendance
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('parent/scores'); ?>">
<i class="bi bi-clipboard-data"></i>
Scores
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('parent/payment'); ?>">
<i class="bi bi-credit-card"></i>
Payment
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('parent/messages'); ?>">
<i class="bi bi-chat-dots"></i>
Messages
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('/calendars'); ?>">
<i class="bi bi-calendar"></i>
Calendar
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('/contact_us'); ?>">
<i class="bi bi-telephone"></i>
Contact Us
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= base_url('/support'); ?>">
<i class="bi bi-life-preserver"></i>
Support
</a>
</li>
</ul>
</div>
</nav>
+43
View File
@@ -0,0 +1,43 @@
<!-- partials/standard_table.php -->
<table class="table table-bordered table-striped">
<thead>
<tr>
<!-- Shared headers -->
<th>#</th>
<th>School ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Gender</th>
<th>Age</th>
<th>Grade</th>
<!-- Custom headers -->
<?php if (!empty($customHeaders)): ?>
<?php foreach ($customHeaders as $header): ?>
<th><?= esc($header) ?></th>
<?php endforeach; ?>
<?php endif; ?>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $i => $row): ?>
<tr>
<td><?= $i + 1 ?></td>
<td><?= esc($row['school_id'] ?? '') ?></td>
<td><?= esc($row['first_name'] ?? '') ?></td>
<td><?= esc($row['last_name'] ?? '') ?></td>
<td><?= esc($row['gender'] ?? '') ?></td>
<td><?= esc($row['age'] ?? '') ?></td>
<td><?= esc($row['Grade'] ?? '') ?></td>
<?php if (!empty($customKeys)): ?>
<?php foreach ($customKeys as $key): ?>
<td><?= esc($row[$key] ?? '') ?></td>
<?php endforeach; ?>
<?php endif; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
+341
View File
@@ -0,0 +1,341 @@
<div class="student-form border rounded p-3 mb-4 bg-light position-relative">
<button type="button" class="btn-close position-absolute end-0 top-0 m-2 js-remove-student" aria-label="Close"></button>
<h5 class="mb-3 text-primary">Student Information</h5>
<div class="col-md-12 mb-3">
<label class="form-label fw-bold mb-2 d-block">
Was your child enrolled in Al Rahma Sunday School last year? <span class="text-danger">*</span>
</label>
<div class="d-flex align-items-center flex-wrap gap-3">
<div class="form-check ps-3">
<input class="form-check-input" type="radio" name="last_year_0" value="yes" data-base-name="last_year" required autocomplete="off">
<label class="form-check-label">Yes</label>
</div>
<div class="form-check ps-3">
<input class="form-check-input" type="radio" name="last_year_0" value="no" data-base-name="last_year" required autocomplete="off">
<label class="form-check-label">No</label>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">First Name <span class="text-danger">*</span></label>
<input
type="text"
class="form-control"
name="studentFirstName[]"
placeholder="First Name"
maxlength="30"
required
data-base-name="studentFirstName"
title="Only letters, spaces, or dashes (230 chars)">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Last Name <span class="text-danger">*</span></label>
<input
type="text"
class="form-control"
name="studentLastName[]"
placeholder="Last Name"
maxlength="30"
required
data-base-name="studentLastName"
title="Only letters, spaces, or dashes (230 chars)">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Date of Birth <span class="text-danger">*</span></label>
<input type="date" class="form-control dob-input" name="dob[]" required data-base-name="dob">
<small class="text-danger age-error d-none">Student must be between 5 and 18 years old.</small>
</div>
<div class="col-6 mb-3">
<label class="form-label grade-label">Last Year Grade <span class="text-danger">*</span></label>
<select class="form-select dynamic-grade grade-select"
name="registration_grade[]"
required data-base-name="registration_grade"
disabled>
<option value="">Select Grade</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Gender <span class="text-danger">*</span></label>
<select class="form-select" name="gender[]" required data-base-name="gender">
<option value="">Select Gender</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Photo Consent <span class="text-danger">*</span></label>
<select class="form-select" name="photo_consent[]" required data-base-name="photo_consent">
<option value="">Select Answer</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<small>
<a href="#" class="text-nowrap" data-bs-toggle="modal" data-bs-target="#picturePolicyModal">
Read Photo Consent Agreement
</a>
</small>
</div>
</div>
<!-- NEW SECTION -->
<div class="row">
<!-- Medical Conditions -->
<div class="col-md-6 mb-3">
<label class="form-label">Medical Conditions (Select all that apply from the 33 items below) <span class="text-danger">*</span></label>
<div class="border rounded p-2 bg-white ps-3" style="max-height: 200px; overflow-y: auto;">
<?php
$medicalOptions = [
"None",
"ADHD (Attention-Deficit/Hyperactivity Disorder)",
"Anxiety or Emotional Disorders",
"Asthma",
"Autism Spectrum Disorder (ASD)",
"Behavioral or Conduct Disorders",
"Blindness / Vision Impairment",
"Celiac Disease (Gluten Intolerance)",
"Cerebral Palsy",
"Cystic Fibrosis",
"Depression",
"Diabetes (Type 1 or Type 2)",
"Down Syndrome",
"Dyslexia or Learning Disabilities",
"Eating Disorders",
"Eczema / Severe Skin Conditions",
"Epilepsy / Seizure Disorders",
"Hearing Impairments / Deafness",
"Heart Conditions (congenital or acquired)",
"Hemophilia / Bleeding Disorders",
"Kidney Disease",
"Migraines / Chronic Headaches",
"Obsessive-Compulsive Disorder (OCD)",
"Physical Disabilities / Mobility Impairments",
"PTSD (Post-Traumatic Stress Disorder)",
"Sickle Cell Anemia",
"Speech and Language Disorders",
"Thyroid Disorders",
"Tourette Syndrome",
"Traumatic Brain Injury (TBI)",
"Rheumatic diseases",
"Ulcerative Colitis / Crohns Disease",
"Other"
];
foreach ($medicalOptions as $opt): ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="medical_conditions[][]" value="<?= esc($opt) ?>" data-base-name="medical_conditions">
<label class="form-check-label ms-1"><?= esc($opt) ?></label>
</div>
<?php endforeach; ?>
</div>
<input type="text" class="form-control mt-2 d-none medical-condition-other" name="medical_condition_other[]" placeholder="Please specify if 'Other' selected">
</div>
<!-- Allergies -->
<div class="col-md-6 mb-3">
<label class="form-label">Allergies (Select all that apply from the 24 items below) <span class="text-danger">*</span></label>
<div class="border rounded p-2 bg-white ps-3" style="max-height: 200px; overflow-y: auto; overflow-x: hidden;">
<?php
$allergyOptions = [
"None",
"Animal Dander (cats, dogs, etc.)",
"Antibiotics",
"Bee stings",
"Cockroach",
"Corn",
"Dust Mites",
"Egg",
"Fire ant stings",
"Fish",
"Fragrances / Perfumes",
"Latex",
"Milk / Dairy",
"Mold",
"Mosquito bites",
"Peanut",
"Pollen (grass, tree, weed)",
"Sesame",
"Shellfish (shrimp, crab, lobster, etc.)",
"Soy",
"Tree Nuts (almond, cashew, walnut, etc.)",
"Wasp stings",
"Wheat / Gluten",
"Other"
];
foreach ($allergyOptions as $opt): ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="allergies[][]" value="<?= esc($opt) ?>" data-base-name="allergies">
<label class="form-check-label ms-1"><?= esc($opt) ?></label>
</div>
<?php endforeach; ?>
</div>
<input type="text" class="form-control mt-2 d-none allergy-other" name="allergy_other[]" placeholder="Please specify if 'Other' selected">
</div>
</div>
</div>
<script>
const gradeOptions = {
public: [{
value: "NA",
text: "Not enrolled in public school"
},
{
value: "KG",
text: "Pre-K / Kindergarten"
},
{
value: "1",
text: "Grade 1"
}, {
value: "2",
text: "Grade 2"
},
{
value: "3",
text: "Grade 3"
}, {
value: "4",
text: "Grade 4"
},
{
value: "5",
text: "Grade 5"
}, {
value: "6",
text: "Grade 6"
},
{
value: "7",
text: "Grade 7"
}, {
value: "8",
text: "Grade 8"
},
{
value: "9",
text: "Grade 9"
}, {
value: "10",
text: "Grade 10"
},
{
value: "11",
text: "Grade 11"
}, {
value: "12",
text: "Grade 12"
}
],
alrahma: [{
value: "KG",
text: "Pre-K / Kindergarten"
},
{
value: "1",
text: "Grade 1"
}, {
value: "2",
text: "Grade 2"
},
{
value: "3",
text: "Grade 3"
}, {
value: "4",
text: "Grade 4"
},
{
value: "5",
text: "Grade 5"
}, {
value: "6",
text: "Grade 6"
},
{
value: "7",
text: "Grade 7"
}, {
value: "8",
text: "Grade 8"
},
{
value: "9",
text: "Grade 9"
}, {
value: "10",
text: "Youth"
}
]
};
function resetGradeSelect(gradeSelect, gradeLabel) {
if (!gradeSelect || !gradeLabel) return;
gradeSelect.innerHTML = '<option value="">Select Grade</option>';
gradeSelect.value = '';
gradeSelect.disabled = true; // keep disabled until a radio is chosen
gradeLabel.innerHTML = 'Last Year Grade <span class="text-danger">*</span>';
}
function populateSelect(gradeSelect, options) {
gradeSelect.innerHTML = '<option value="">Select Grade</option>';
options.forEach(o => {
const opt = document.createElement('option');
opt.value = o.value;
opt.textContent = o.text;
gradeSelect.appendChild(opt);
});
}
function updateGradeOptions(studentForm, type) {
const gradeSelect = studentForm.querySelector('.grade-select');
const gradeLabel = studentForm.querySelector('.grade-label');
if (!gradeSelect || !gradeLabel) return;
gradeSelect.disabled = false; // enable now that a choice was made
gradeSelect.value = ''; // clear any stale selection
if (type === 'yes') {
gradeLabel.innerHTML = 'Al Rahma School Last Year Grade <span class="text-danger">*</span>';
populateSelect(gradeSelect, gradeOptions.alrahma);
} else if (type === 'no') {
gradeLabel.innerHTML = 'Public School Last Year Grade <span class="text-danger">*</span>';
populateSelect(gradeSelect, gradeOptions.public);
} else {
resetGradeSelect(gradeSelect, gradeLabel);
}
}
// Event: when a radio is chosen, update this form's select
document.addEventListener('change', function(e) {
if (e.target.matches('input[type="radio"][data-base-name="last_year"]')) {
const form = e.target.closest('.student-form');
if (form && e.target.checked) {
updateGradeOptions(form, e.target.value);
}
}
});
// On load: enforce disabled unless a radio is already checked (server repopulation)
(function initStudentForms() {
const forms = document.querySelectorAll('.student-form');
forms.forEach(form => {
const gradeSelect = form.querySelector('.grade-select');
const gradeLabel = form.querySelector('.grade-label');
// Start disabled (HTML already has disabled, but enforce from JS too)
resetGradeSelect(gradeSelect, gradeLabel);
// If a radio is already checked (e.g., after validation error), enable/populate accordingly
const checked = form.querySelector('input[type="radio"][data-base-name="last_year"]:checked');
if (checked) {
updateGradeOptions(form, checked.value);
}
});
})();
</script>