230 lines
11 KiB
PHP
230 lines
11 KiB
PHP
<?php
|
|
require_once __DIR__ . '/db/config.php';
|
|
session_start();
|
|
|
|
$db = db();
|
|
$pageTitle = 'Parent Portal | SOMS';
|
|
$learner = null;
|
|
$school = null;
|
|
$attendance_history = [];
|
|
$assessment_results = [];
|
|
$school_events = [];
|
|
$search_id = $_GET['student_id'] ?? '';
|
|
|
|
if ($search_id) {
|
|
// Fetch Learner and School
|
|
$stmt = $db->prepare("SELECT l.*, s.name as school_name
|
|
FROM learners l
|
|
JOIN schools s ON l.school_id = s.id
|
|
WHERE l.student_id = ?");
|
|
$stmt->execute([$search_id]);
|
|
$learner = $stmt->fetch();
|
|
|
|
if ($learner) {
|
|
// Fetch Attendance History (Last 30 days)
|
|
$stmt = $db->prepare("SELECT * FROM attendance WHERE learner_id = ? ORDER BY date DESC LIMIT 30");
|
|
$stmt->execute([$learner['id']]);
|
|
$attendance_history = $stmt->fetchAll();
|
|
|
|
// Fetch Assessment Results
|
|
$stmt = $db->prepare("
|
|
SELECT a.name, a.type, a.total_marks, m.marks_obtained, a.created_at
|
|
FROM marks m
|
|
JOIN assessments a ON m.assessment_id = a.id
|
|
WHERE m.learner_id = ?
|
|
ORDER BY a.created_at DESC
|
|
");
|
|
$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();
|
|
}
|
|
}
|
|
|
|
include 'includes/header.php';
|
|
?>
|
|
|
|
<div class="container pb-5">
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h2 class="h4 mb-1">Parent Engagement Portal</h2>
|
|
<p class="text-muted small">Stay updated on your child's progress with minimal data usage.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-md-4">
|
|
<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">
|
|
<label class="form-label small fw-bold">Student ID / National ID</label>
|
|
<input type="text" name="student_id" class="form-control" placeholder="e.g. STU10023" value="<?= htmlspecialchars($search_id) ?>" required>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary w-100 fw-bold">
|
|
<i class="bi bi-search me-2"></i> View Progress
|
|
</button>
|
|
</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.
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="col-md-8">
|
|
<?php if ($learner): ?>
|
|
<div class="card mb-4 shadow-sm border-0">
|
|
<div class="card-header bg-white py-3">
|
|
<h5 class="mb-0 fw-bold"><?= htmlspecialchars($learner['full_name']) ?></h5>
|
|
<small class="text-muted"><?= htmlspecialchars($learner['school_name']) ?></small>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row text-center">
|
|
<div class="col-4 border-end">
|
|
<p class="text-muted small mb-1">Grade</p>
|
|
<h6 class="fw-bold"><?= htmlspecialchars($learner['grade']) ?></h6>
|
|
</div>
|
|
<div class="col-4 border-end">
|
|
<p class="text-muted small mb-1">Attendance (30d)</p>
|
|
<?php
|
|
$total = count($attendance_history);
|
|
$present = 0;
|
|
foreach ($attendance_history as $a) if ($a['status'] === 'present') $present++;
|
|
$rate = $total > 0 ? round(($present / $total) * 100) : 0;
|
|
?>
|
|
<h6 class="fw-bold"><?= $rate ?>%</h6>
|
|
</div>
|
|
<div class="col-4">
|
|
<p class="text-muted small mb-1">Academic Avg</p>
|
|
<?php
|
|
$total_perc = 0;
|
|
$count = 0;
|
|
foreach ($assessment_results as $res) {
|
|
$total_perc += ($res['marks_obtained'] / $res['total_marks']) * 100;
|
|
$count++;
|
|
}
|
|
$avg = $count > 0 ? round($total_perc / $count, 1) : 0;
|
|
?>
|
|
<h6 class="fw-bold text-primary"><?= $avg ?>%</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabs for Attendance vs Results -->
|
|
<ul class="nav nav-tabs border-0 mb-3" id="parentTabs" role="tablist">
|
|
<li class="nav-item">
|
|
<button class="nav-link active border-0 fw-bold" id="attendance-tab" data-bs-toggle="tab" data-bs-target="#attendance" type="button">Attendance</button>
|
|
</li>
|
|
<li class="nav-item">
|
|
<button class="nav-link border-0 fw-bold" id="results-tab" data-bs-toggle="tab" data-bs-target="#results" type="button">Academic Results</button>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content bg-white rounded shadow-sm">
|
|
<div class="tab-pane fade show active" id="attendance">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">Date</th>
|
|
<th class="text-end pe-4">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($attendance_history)): ?>
|
|
<tr>
|
|
<td colspan="2" class="text-center py-4 text-muted">No attendance records found for the last 30 days.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<?php foreach ($attendance_history as $record): ?>
|
|
<tr>
|
|
<td class="ps-4"><?= date('l, d M Y', strtotime($record['date'])) ?></td>
|
|
<td class="text-end pe-4">
|
|
<?php if ($record['status'] === 'present'): ?>
|
|
<span class="badge bg-success">Present</span>
|
|
<?php else: ?>
|
|
<span class="badge bg-danger">Absent</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="tab-pane fade" id="results">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">Assessment</th>
|
|
<th>Score</th>
|
|
<th class="text-end pe-4">Percentage</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($assessment_results)): ?>
|
|
<tr>
|
|
<td colspan="3" class="text-center py-4 text-muted">No assessment results recorded yet.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<?php foreach ($assessment_results as $res):
|
|
$p = round(($res['marks_obtained'] / $res['total_marks']) * 100, 1);
|
|
?>
|
|
<tr>
|
|
<td class="ps-4">
|
|
<strong><?= htmlspecialchars($res['name']) ?></strong>
|
|
<br><small class="text-muted"><?= htmlspecialchars($res['type']) ?> (<?= date('d M Y', strtotime($res['created_at'])) ?>)</small>
|
|
</td>
|
|
<td><?= $res['marks_obtained'] ?> / <?= $res['total_marks'] ?></td>
|
|
<td class="text-end pe-4 fw-bold <?= $p >= 50 ? 'text-success' : 'text-danger' ?>">
|
|
<?= $p ?>%
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="h-100 d-flex flex-column align-items-center justify-content-center text-muted py-5 border rounded bg-white shadow-sm">
|
|
<i class="bi bi-person-badge mb-3" style="font-size: 3rem; opacity: 0.3;"></i>
|
|
<p>Please enter a Student ID to view your child's progress.</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php include 'includes/footer.php'; ?>
|