recreate project
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 school’s 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>
|
||||
@@ -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-->
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 (2–30 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 (2–30 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 / Crohn’s 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>
|
||||
Reference in New Issue
Block a user