This commit is contained in:
Flatlogic Bot 2026-01-30 15:02:53 +00:00
parent 57a1969d5e
commit 7a517224e6
9 changed files with 702 additions and 4 deletions

View File

@ -138,6 +138,9 @@ include 'includes/header.php';
<a href="bulk-upload.php" class="btn btn-outline-primary text-start">
<i class="bi bi-upload me-2"></i> Bulk Upload Learners
</a>
<a href="events.php" class="btn btn-outline-primary text-start">
<i class="bi bi-calendar-event me-2"></i> Schedule School Event
</a>
<a href="reports.php" class="btn btn-outline-primary text-start">
<i class="bi bi-file-earmark-bar-graph me-2"></i> Academic Reports
</a>
@ -151,4 +154,4 @@ include 'includes/header.php';
</div>
</div>
<?php include 'includes/footer.php'; ?>
<?php include 'includes/footer.php'; ?>

122
analytics.php Normal file
View File

@ -0,0 +1,122 @@
<?php
session_start();
require_once 'db/config.php';
if (!isset($_SESSION['user_id']) || !in_array($_SESSION['role'], ['Admin', 'Teacher', 'Super Admin'])) {
header('Location: login.php');
exit;
}
$school_id = $_SESSION['school_id'];
$role = $_SESSION['role'];
// Fetch grade-level averages
$query = "
SELECT
l.grade,
AVG((m.marks_obtained / a.total_marks) * 100) as average_percentage,
COUNT(DISTINCT l.id) as student_count,
COUNT(DISTINCT a.id) as assessment_count
FROM learners l
JOIN marks m ON l.id = m.learner_id
JOIN assessments a ON m.assessment_id = a.id
WHERE l.school_id = :school_id
GROUP BY l.grade
ORDER BY l.grade ASC
";
$stmt = db()->prepare($query);
$stmt->execute(['school_id' => $school_id]);
$grade_stats = $stmt->fetchAll();
$pageTitle = "Grade Performance Analytics";
include 'includes/header.php';
?>
<div class="container mt-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-bar-chart-line me-2"></i>Grade Performance Analytics</h2>
<button onclick="window.print()" class="btn btn-outline-primary d-print-none">
<i class="bi bi-printer me-2"></i>Print Report
</button>
</div>
<div class="row">
<div class="col-md-12 mb-4">
<div class="card shadow-sm border-0">
<div class="card-body">
<h5 class="card-title mb-4">Grade-Level Comparison</h5>
<?php if (empty($grade_stats)): ?>
<div class="alert alert-info">No assessment data available for comparison yet.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th>Grade</th>
<th>Avg. Performance</th>
<th>Students</th>
<th>Assessments</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<?php foreach ($grade_stats as $stat): ?>
<?php
$avg = round($stat['average_percentage'], 1);
$badgeClass = $avg >= 70 ? 'bg-success' : ($avg >= 50 ? 'bg-warning text-dark' : 'bg-danger');
?>
<tr>
<td class="fw-bold"><?php echo htmlspecialchars($stat['grade']); ?></td>
<td>
<div class="d-flex align-items-center">
<div class="progress flex-grow-1 me-3" style="height: 10px;">
<div class="progress-bar <?php echo $badgeClass; ?>" role="progressbar" style="width: <?php echo $avg; ?>%"></div>
</div>
<span class="fw-bold"><?php echo $avg; ?>%</span>
</div>
</td>
<td><?php echo $stat['student_count']; ?></td>
<td><?php echo $stat['assessment_count']; ?></td>
<td>
<span class="badge <?php echo $badgeClass; ?>">
<?php echo $avg >= 70 ? 'Excellent' : ($avg >= 50 ? 'Satisfactory' : 'Critical'); ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-6 mb-4">
<div class="card h-100 shadow-sm border-0 bg-light">
<div class="card-body">
<h6><i class="bi bi-info-circle me-2"></i>Insights</h6>
<p class="text-muted small">
This data represents the average score across all subjects and assessments for each grade level in your school.
Use this to identify grades that may require additional resources or intervention.
</p>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100 shadow-sm border-0 bg-light">
<div class="card-body">
<h6><i class="bi bi-lightbulb me-2"></i>Recommendations</h6>
<ul class="text-muted small">
<li>Grades below 50% should be flagged for curriculum review.</li>
<li>High-performing grades can serve as models for peer-teacher coaching.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<?php include 'includes/footer.php'; ?>

244
collaboration.php Normal file
View File

@ -0,0 +1,244 @@
<?php
session_start();
require_once 'db/config.php';
if (!isset($_SESSION['user_id']) || !in_array($_SESSION['role'], ['Admin', 'Teacher', 'Super Admin'])) {
header('Location: login.php');
exit;
}
$user_id = $_SESSION['user_id'];
$school_id = $_SESSION['school_id'];
$success = '';
$error = '';
// Handle Resource Upload
if (isset($_POST['upload_resource'])) {
$title = $_POST['title'];
$description = $_POST['description'];
$grade = $_POST['grade'];
$subject = $_POST['subject'];
// In a real app, we'd handle file uploads. For this demo, we'll just store the metadata.
try {
$stmt = db()->prepare("INSERT INTO resources (title, description, teacher_id, school_id, grade, subject) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$title, $description, $user_id, $school_id, $grade, $subject]);
$success = "Resource shared successfully!";
} catch (PDOException $e) {
$error = "Failed to share resource: " . $e->getMessage();
}
}
// Handle Forum Post
if (isset($_POST['create_post'])) {
$title = $_POST['title'];
$content = $_POST['content'];
try {
$stmt = db()->prepare("INSERT INTO forum_posts (title, content, author_id, school_id) VALUES (?, ?, ?, ?)");
$stmt->execute([$title, $content, $user_id, $school_id]);
$success = "Topic posted successfully!";
} catch (PDOException $e) {
$error = "Failed to post topic: " . $e->getMessage();
}
}
// Fetch Resources
$resources = db()->prepare("SELECT r.*, u.email as teacher_email FROM resources r JOIN users u ON r.teacher_id = u.id WHERE r.school_id = ? ORDER BY r.created_at DESC");
$resources->execute([$school_id]);
$resources = $resources->fetchAll();
// Fetch Forum Posts
$posts = db()->prepare("SELECT p.*, u.email as author_email, (SELECT COUNT(*) FROM forum_comments WHERE post_id = p.id) as comment_count FROM forum_posts p JOIN users u ON p.author_id = u.id WHERE p.school_id = ? ORDER BY p.created_at DESC");
$posts->execute([$school_id]);
$posts = $posts->fetchAll();
$pageTitle = "Teacher Collaboration Hub";
include 'includes/header.php';
?>
<div class="container mt-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-people-fill me-2"></i>Collaboration Hub</h2>
<div class="btn-group">
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadModal">
<i class="bi bi-upload me-2"></i>Share Resource
</button>
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#postModal">
<i class="bi bi-chat-dots me-2"></i>New Topic
</button>
</div>
</div>
<?php if ($success): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?php echo $success; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<ul class="nav nav-tabs mb-4" id="hubTabs" role="tablist">
<li class="nav-item">
<button class="nav-link active" id="resources-tab" data-bs-toggle="tab" data-bs-target="#resources" type="button" role="tab">Resources</button>
</li>
<li class="nav-item">
<button class="nav-link" id="forum-tab" data-bs-toggle="tab" data-bs-target="#forum" type="button" role="tab">Discussion Forum</button>
</li>
</ul>
<div class="tab-content" id="hubTabsContent">
<!-- Resources Tab -->
<div class="tab-pane fade show active" id="resources" role="tabpanel">
<div class="row">
<?php if (empty($resources)): ?>
<div class="col-12 text-center py-5">
<i class="bi bi-folder2-open display-1 text-light"></i>
<p class="mt-3 text-muted">No resources shared yet. Be the first!</p>
</div>
<?php else: ?>
<?php foreach ($resources as $res): ?>
<div class="col-md-4 mb-4">
<div class="card h-100 shadow-sm border-0">
<div class="card-body">
<div class="d-flex justify-content-between mb-2">
<span class="badge bg-light text-dark"><?php echo htmlspecialchars($res['subject']); ?></span>
<span class="badge bg-light text-dark">Grade <?php echo htmlspecialchars($res['grade']); ?></span>
</div>
<h5 class="card-title"><?php echo htmlspecialchars($res['title']); ?></h5>
<p class="card-text text-muted small"><?php echo htmlspecialchars($res['description']); ?></p>
</div>
<div class="card-footer bg-white border-0 py-3">
<div class="d-flex align-items-center mb-3">
<div class="flex-shrink-0">
<i class="bi bi-person-circle fs-4 text-primary"></i>
</div>
<div class="flex-grow-1 ms-2">
<div class="small fw-bold"><?php echo explode('@', $res['teacher_email'])[0]; ?></div>
<div class="text-muted smaller"><?php echo date('M d, Y', strtotime($res['created_at'])); ?></div>
</div>
</div>
<button class="btn btn-sm btn-outline-primary w-100">
<i class="bi bi-download me-2"></i>Download Resource
</button>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Forum Tab -->
<div class="tab-pane fade" id="forum" role="tabpanel">
<div class="card shadow-sm border-0">
<div class="list-group list-group-flush">
<?php if (empty($posts)): ?>
<div class="text-center py-5">
<i class="bi bi-chat-left-dots display-1 text-light"></i>
<p class="mt-3 text-muted">Start a conversation with your colleagues.</p>
</div>
<?php else: ?>
<?php foreach ($posts as $post): ?>
<a href="#" class="list-group-item list-group-item-action py-4 border-0 border-bottom">
<div class="d-flex w-100 justify-content-between align-items-start">
<div class="me-3">
<h5 class="mb-1"><?php echo htmlspecialchars($post['title']); ?></h5>
<p class="mb-1 text-muted"><?php echo htmlspecialchars(substr($post['content'], 0, 150)) . '...'; ?></p>
<div class="small mt-2">
<span class="text-primary fw-bold"><?php echo explode('@', $post['author_email'])[0]; ?></span>
<span class="text-muted ms-2"> <?php echo date('M d, Y', strtotime($post['created_at'])); ?></span>
</div>
</div>
<div class="text-end">
<span class="badge rounded-pill bg-light text-primary px-3 py-2">
<i class="bi bi-chat-fill me-1"></i> <?php echo $post['comment_count']; ?>
</span>
</div>
</div>
</a>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<!-- Upload Modal -->
<div class="modal fade" id="uploadModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header border-0">
<h5 class="modal-title">Share Learning Resource</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Resource Title</label>
<input type="text" name="title" class="form-control" required placeholder="e.g. Grade 10 Math Exam Prep">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Grade</label>
<select name="grade" class="form-select" required>
<option value="8">Grade 8</option>
<option value="9">Grade 9</option>
<option value="10">Grade 10</option>
<option value="11">Grade 11</option>
<option value="12">Grade 12</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Subject</label>
<input type="text" name="subject" class="form-control" required placeholder="e.g. Mathematics">
</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea name="description" class="form-control" rows="3" placeholder="Briefly describe the resource..."></textarea>
</div>
<div class="mb-3">
<label class="form-label">File (Placeholder)</label>
<input type="file" class="form-control" disabled>
<small class="text-muted">File upload disabled for prototype.</small>
</div>
</div>
<div class="modal-footer border-0">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="upload_resource" class="btn btn-primary">Upload & Share</button>
</div>
</form>
</div>
</div>
</div>
<!-- Post Modal -->
<div class="modal fade" id="postModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header border-0">
<h5 class="modal-title">Start Discussion Topic</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Topic Title</label>
<input type="text" name="title" class="form-control" required placeholder="What do you want to discuss?">
</div>
<div class="mb-3">
<label class="form-label">Content</label>
<textarea name="content" class="form-control" rows="5" required placeholder="Share your thoughts or ask a question..."></textarea>
</div>
</div>
<div class="modal-footer border-0">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="create_post" class="btn btn-primary">Post Topic</button>
</div>
</form>
</div>
</div>
</div>
<?php include 'includes/footer.php'; ?>

View File

@ -0,0 +1,35 @@
-- Migration: Add tables for Teacher Collaboration Hub
CREATE TABLE IF NOT EXISTS resources (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
file_path VARCHAR(255),
teacher_id INT NOT NULL,
school_id INT NOT NULL,
grade VARCHAR(20),
subject VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (school_id) REFERENCES schools(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS forum_posts (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
author_id INT NOT NULL,
school_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (school_id) REFERENCES schools(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS forum_comments (
id INT AUTO_INCREMENT PRIMARY KEY,
post_id INT NOT NULL,
author_id INT NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (post_id) REFERENCES forum_posts(id) ON DELETE CASCADE,
FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE
);

View File

@ -0,0 +1,15 @@
-- Migration: Add events table for scheduling
CREATE TABLE IF NOT EXISTS events (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
event_type ENUM('Meeting', 'Conference', 'Workshop', 'Holiday', 'Other') NOT NULL DEFAULT 'Meeting',
start_datetime DATETIME NOT NULL,
end_datetime DATETIME NOT NULL,
location VARCHAR(255),
created_by INT NOT NULL,
school_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (school_id) REFERENCES schools(id) ON DELETE CASCADE
);

229
events.php Normal file
View File

@ -0,0 +1,229 @@
<?php
require_once __DIR__ . '/db/config.php';
session_start();
// Auth Check - everyone logged in can see events
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
$db = db();
$school_id = $_SESSION['school_id'];
$user_id = $_SESSION['user_id'];
$user_role = $_SESSION['role'];
$message = '';
$pageTitle = 'School Events | SOMS';
// Handle Event Creation
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_event'])) {
if (in_array($user_role, ['Admin', 'Teacher', 'Super Admin'])) {
$title = $_POST['title'] ?? '';
$description = $_POST['description'] ?? '';
$event_type = $_POST['event_type'] ?? 'Meeting';
$start_datetime = $_POST['start_datetime'] ?? '';
$end_datetime = $_POST['end_datetime'] ?? '';
$location = $_POST['location'] ?? '';
if ($title && $start_datetime && $end_datetime) {
try {
$stmt = $db->prepare("INSERT INTO events (title, description, event_type, start_datetime, end_datetime, location, created_by, school_id)
VALUES (:title, :description, :event_type, :start_datetime, :end_datetime, :location, :created_by, :school_id)");
$stmt->execute([
'title' => $title,
'description' => $description,
'event_type' => $event_type,
'start_datetime' => $start_datetime,
'end_datetime' => $end_datetime,
'location' => $location,
'created_by' => $user_id,
'school_id' => $school_id
]);
$message = "Event created successfully!";
} catch (Exception $e) {
$message = "Error: " . $e->getMessage();
}
} else {
$message = "Please fill in all required fields.";
}
}
}
// Fetch Upcoming Events
$stmt = $db->prepare("SELECT e.*, u.email as creator_email
FROM events e
JOIN users u ON e.created_by = u.id
WHERE e.school_id = :school_id AND e.end_datetime >= NOW()
ORDER BY e.start_datetime ASC");
$stmt->execute(['school_id' => $school_id]);
$upcoming_events = $stmt->fetchAll();
// Fetch Past Events
$stmt = $db->prepare("SELECT e.*, u.email as creator_email
FROM events e
JOIN users u ON e.created_by = u.id
WHERE e.school_id = :school_id AND e.end_datetime < NOW()
ORDER BY e.start_datetime DESC LIMIT 10");
$stmt->execute(['school_id' => $school_id]);
$past_events = $stmt->fetchAll();
include 'includes/header.php';
?>
<div class="container pb-5">
<div class="row mb-4">
<div class="col-md-8">
<h2 class="h4 mb-1">School Events & Scheduling</h2>
<p class="text-muted small">Stay updated with meetings, conferences, and school holidays.</p>
</div>
<?php if (in_array($user_role, ['Admin', 'Teacher', 'Super Admin'])): ?>
<div class="col-md-4 text-md-end">
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addEventModal">
<i class="bi bi-calendar-plus me-2"></i>Schedule Event
</button>
</div>
<?php endif; ?>
</div>
<?php if ($message): ?>
<div class="alert alert-info alert-dismissible fade show" role="alert">
<?= htmlspecialchars($message) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<div class="row">
<!-- Upcoming Events -->
<div class="col-lg-8">
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white py-3">
<h5 class="mb-0">Upcoming Events</h5>
</div>
<div class="card-body p-0">
<?php if (empty($upcoming_events)): ?>
<div class="p-5 text-center text-muted">
<i class="bi bi-calendar-event display-4 mb-3 d-block"></i>
<p>No upcoming events scheduled.</p>
</div>
<?php else: ?>
<div class="list-group list-group-flush">
<?php foreach ($upcoming_events as $event): ?>
<div class="list-group-item p-4">
<div class="d-flex w-100 justify-content-between align-items-start mb-2">
<div>
<span class="badge bg-soft-primary text-primary mb-2"><?= htmlspecialchars($event['event_type']) ?></span>
<h5 class="mb-1"><?= htmlspecialchars($event['title']) ?></h5>
</div>
<small class="text-muted">
<?= date('D, d M Y', strtotime($event['start_datetime'])) ?>
</small>
</div>
<p class="mb-2 text-muted"><?= nl2br(htmlspecialchars($event['description'])) ?></p>
<div class="d-flex align-items-center small text-muted">
<span class="me-3"><i class="bi bi-clock me-1"></i> <?= date('H:i', strtotime($event['start_datetime'])) ?> - <?= date('H:i', strtotime($event['end_datetime'])) ?></span>
<?php if ($event['location']): ?>
<span class="me-3"><i class="bi bi-geo-alt me-1"></i> <?= htmlspecialchars($event['location']) ?></span>
<?php endif; ?>
<span><i class="bi bi-person me-1"></i> <?= htmlspecialchars($event['creator_email']) ?></span>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
<!-- Past Events / Sidebar -->
<div class="col-lg-4">
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white py-3">
<h5 class="mb-0">Recently Concluded</h5>
</div>
<div class="card-body p-0">
<?php if (empty($past_events)): ?>
<div class="p-4 text-center text-muted small">
No past events found.
</div>
<?php else: ?>
<div class="list-group list-group-flush small">
<?php foreach ($past_events as $event): ?>
<div class="list-group-item border-0 border-bottom">
<div class="fw-bold"><?= htmlspecialchars($event['title']) ?></div>
<div class="text-muted"><?= date('d M Y', strtotime($event['start_datetime'])) ?></div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
<div class="card bg-primary text-white shadow-sm border-0">
<div class="card-body">
<h6>Need a Private Meeting?</h6>
<p class="small mb-0">Parents can request specific slots for parent-teacher conferences via the direct message system in the Hub.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Add Event Modal -->
<div class="modal fade" id="addEventModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST">
<div class="modal-header">
<h5 class="modal-title">Schedule New Event</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Event Title *</label>
<input type="text" name="title" class="form-control" required placeholder="e.g. Parent-Teacher Conference">
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">Event Type</label>
<select name="event_type" class="form-select">
<option value="Meeting">Meeting</option>
<option value="Conference">Conference</option>
<option value="Workshop">Workshop</option>
<option value="Holiday">Holiday</option>
<option value="Other">Other</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Location</label>
<input type="text" name="location" class="form-control" placeholder="e.g. Room 102 / Zoom">
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">Start Date & Time *</label>
<input type="datetime-local" name="start_datetime" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label">End Date & Time *</label>
<input type="datetime-local" name="end_datetime" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea name="description" class="form-control" rows="3" placeholder="Additional details about the event..."></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="create_event" class="btn btn-primary">Create Event</button>
</div>
</form>
</div>
</div>
</div>
<style>
.bg-soft-primary { background-color: rgba(13, 110, 253, 0.1); }
</style>
<?php include 'includes/footer.php'; ?>

View File

@ -61,6 +61,12 @@ $is_logged_in = isset($_SESSION['user_id']);
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'assessments.php' ? 'active' : '' ?>" href="assessments.php">Assessments</a>
</li>
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'analytics.php' ? 'active' : '' ?>" href="analytics.php">Analytics</a>
</li>
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'collaboration.php' ? 'active' : '' ?>" href="collaboration.php">Hub</a>
</li>
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'reports.php' ? 'active' : '' ?>" href="reports.php">Reports</a>
</li>
@ -73,6 +79,12 @@ $is_logged_in = isset($_SESSION['user_id']);
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'learners.php' ? 'active' : '' ?>" href="learners.php">Learners</a>
</li>
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'analytics.php' ? 'active' : '' ?>" href="analytics.php">Analytics</a>
</li>
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'collaboration.php' ? 'active' : '' ?>" href="collaboration.php">Hub</a>
</li>
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'reports.php' ? 'active' : '' ?>" href="reports.php">Reports</a>
</li>
@ -89,6 +101,12 @@ $is_logged_in = isset($_SESSION['user_id']);
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'parent.php' ? 'active' : '' ?>" href="parent.php">Parent Portal</a>
</li>
<?php endif; ?>
<?php if ($is_logged_in): ?>
<li class="nav-item">
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'events.php' ? 'active' : '' ?>" href="events.php">Events</a>
</li>
<?php endif; ?>
</ul>
<div class="d-flex align-items-center">
<?php if ($is_logged_in): ?>

View File

@ -8,6 +8,7 @@ $learner = null;
$school = null;
$attendance_history = [];
$assessment_results = [];
$school_events = [];
$search_id = $_GET['student_id'] ?? '';
if ($search_id) {
@ -35,6 +36,11 @@ if ($search_id) {
");
$stmt->execute([$learner['id']]);
$assessment_results = $stmt->fetchAll();
// Fetch Upcoming School Events
$stmt = $db->prepare("SELECT * FROM events WHERE school_id = ? AND end_datetime >= NOW() ORDER BY start_datetime ASC LIMIT 3");
$stmt->execute([$learner['school_id']]);
$school_events = $stmt->fetchAll();
}
}
@ -51,7 +57,7 @@ include 'includes/header.php';
<div class="row g-4">
<div class="col-md-4">
<div class="card p-4 shadow-sm border-0">
<div class="card p-4 shadow-sm border-0 mb-4">
<h5 class="mb-3 fw-bold">Find My Child</h5>
<form method="GET">
<div class="mb-3">
@ -64,6 +70,29 @@ include 'includes/header.php';
</form>
</div>
<?php if ($learner && !empty($school_events)): ?>
<div class="card shadow-sm border-0">
<div class="card-header bg-white py-3">
<h6 class="mb-0 fw-bold">Upcoming School Events</h6>
</div>
<div class="card-body p-0">
<div class="list-group list-group-flush small">
<?php foreach ($school_events as $event): ?>
<div class="list-group-item">
<div class="fw-bold"><?= htmlspecialchars($event['title']) ?></div>
<div class="text-muted small">
<i class="bi bi-calendar-event me-1"></i> <?= date('d M, H:i', strtotime($event['start_datetime'])) ?>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="p-3">
<a href="events.php" class="btn btn-sm btn-outline-primary w-100">View All Events</a>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($search_id && !$learner): ?>
<div class="alert alert-warning mt-3 shadow-sm">
<i class="bi bi-exclamation-triangle me-2"></i> No learner found with ID <strong><?= htmlspecialchars($search_id) ?></strong>. Please contact the school office.
@ -198,4 +227,4 @@ include 'includes/header.php';
</div>
</div>
<?php include 'includes/footer.php'; ?>
<?php include 'includes/footer.php'; ?>

5
sw.js
View File

@ -1,4 +1,4 @@
const CACHE_NAME = 'township-schools-v5';
const CACHE_NAME = 'township-schools-v7';
const STATIC_ASSETS = [
'/',
'/index.php',
@ -11,6 +11,9 @@ const STATIC_ASSETS = [
'/reports.php',
'/bulk-upload.php',
'/notifications.php',
'/analytics.php',
'/collaboration.php',
'/events.php',
'/parent.php',
'/assets/css/custom.css',
'/assets/js/main.js',