<?php
$pageTitle = "Attendance Report";
include_once('includes/header.php');
// Check if student is logged in
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'student') {
header("Location: ../login.php");
exit();
}
$userId = $_SESSION['user_id'];
// Get course enrollments for filter dropdown
$courses_query = "
SELECT c.id, c.title
FROM courses c
INNER JOIN enrollments e ON c.id = e.course_id
WHERE e.user_id = ? AND e.status = 'active'
ORDER BY c.title
";
$stmt = $conn->prepare($courses_query);
$stmt->bind_param("i", $userId);
$stmt->execute();
$courses_result = $stmt->get_result();
$courses = [];
while ($row = $courses_result->fetch_assoc()) {
$courses[] = $row;
}
// Default filter for current month
$selected_month = date('m');
$selected_year = date('Y');
$selected_course = 0; // 0 means all courses
// Apply filters if submitted
if (isset($_GET['filter'])) {
$selected_month = isset($_GET['month']) ? $_GET['month'] : date('m');
$selected_year = isset($_GET['year']) ? $_GET['year'] : date('Y');
$selected_course = isset($_GET['course_id']) ? intval($_GET['course_id']) : 0;
}
// Fetch attendance data based on filters
$attendance_query = "
SELECT a.id, a.date, a.status, a.notes, c.title as course_title
FROM attendance a
INNER JOIN enrollments e ON a.enrollment_id = e.id
INNER JOIN courses c ON e.course_id = c.id
WHERE e.user_id = ?
";
// Add filter conditions
if ($selected_course > 0) {
$attendance_query .= " AND e.course_id = ?";
}
if ($selected_month > 0) {
$attendance_query .= " AND MONTH(a.date) = ?";
}
if ($selected_year > 0) {
$attendance_query .= " AND YEAR(a.date) = ?";
}
$attendance_query .= " ORDER BY a.date DESC";
// Prepare and bind parameters
$stmt = $conn->prepare($attendance_query);
$param_types = "i";
$params = [$userId];
if ($selected_course > 0) {
$param_types .= "i";
$params[] = $selected_course;
}
if ($selected_month > 0) {
$param_types .= "i";
$params[] = $selected_month;
}
if ($selected_year > 0) {
$param_types .= "i";
$params[] = $selected_year;
}
// Dynamic bind_param
$stmt->bind_param($param_types, ...$params);
$stmt->execute();
$attendance_result = $stmt->get_result();
$attendance_records = [];
while ($row = $attendance_result->fetch_assoc()) {
$attendance_records[] = $row;
}
// Calculate statistics
$total_records = count($attendance_records);
$present_count = 0;
$absent_count = 0;
$late_count = 0;
$excused_count = 0;
$daily_status = [];
$course_stats = [];
foreach ($attendance_records as $record) {
$date = date('Y-m-d', strtotime($record['date']));
$course = $record['course_title'];
// Count by status
if ($record['status'] === 'present') {
$present_count++;
} elseif ($record['status'] === 'absent') {
$absent_count++;
} elseif ($record['status'] === 'late') {
$late_count++;
} elseif ($record['status'] === 'excused') {
$excused_count++;
}
// Prepare data for daily chart
if (!isset($daily_status[$date])) {
$daily_status[$date] = ['present' => 0, 'absent' => 0, 'late' => 0, 'excused' => 0];
}
$daily_status[$date][$record['status']]++;
// Prepare data for course-wise chart
if (!isset($course_stats[$course])) {
$course_stats[$course] = ['present' => 0, 'absent' => 0, 'late' => 0, 'excused' => 0, 'total' => 0];
}
$course_stats[$course][$record['status']]++;
$course_stats[$course]['total']++;
}
// Prepare chart data
$dates = array_keys($daily_status);
$present_data = array_column(array_values($daily_status), 'present');
$absent_data = array_column(array_values($daily_status), 'absent');
$late_data = array_column(array_values($daily_status), 'late');
$excused_data = array_column(array_values($daily_status), 'excused');
$course_names = array_keys($course_stats);
$course_attendance_percent = [];
foreach ($course_names as $course_name) {
$total = $course_stats[$course_name]['total'];
if ($total > 0) {
$course_attendance_percent[$course_name] = round(($course_stats[$course_name]['present'] / $total) * 100, 1);
} else {
$course_attendance_percent[$course_name] = 0;
}
}
// Calculate attendance percentage
$attendance_percentage = $total_records > 0 ? round(($present_count / $total_records) * 100, 1) : 0;
?>
<div class="container py-4">
<h2 class="mb-4">Attendance Report</h2>
<!-- Filter Form -->
<div class="card mb-4">
<div class="card-body">
<form method="GET" class="row g-3">
<div class="col-md-3">
<label for="course_id" class="form-label">Course</label>
<select class="form-select" id="course_id" name="course_id">
<option value="0" <?php echo $selected_course == 0 ? 'selected' : ''; ?>>All Courses</option>
<?php foreach ($courses as $course): ?>
<option value="<?php echo $course['id']; ?>" <?php echo $selected_course == $course['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($course['title']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label for="month" class="form-label">Month</label>
<select class="form-select" id="month" name="month">
<option value="0" <?php echo $selected_month == 0 ? 'selected' : ''; ?>>All Months</option>
<?php for ($i = 1; $i <= 12; $i++): ?>
<option value="<?php echo $i; ?>" <?php echo $selected_month == $i ? 'selected' : ''; ?>>
<?php echo date('F', mktime(0, 0, 0, $i, 1)); ?>
</option>
<?php endfor; ?>
</select>
</div>
<div class="col-md-3">
<label for="year" class="form-label">Year</label>
<select class="form-select" id="year" name="year">
<?php for ($i = date('Y'); $i >= date('Y') - 5; $i--): ?>
<option value="<?php echo $i; ?>" <?php echo $selected_year == $i ? 'selected' : ''; ?>>
<?php echo $i; ?>
</option>
<?php endfor; ?>
</select>
</div>
<div class="col-md-3 d-flex align-items-end">
<button type="submit" name="filter" class="btn btn-primary w-100">Apply Filter</button>
</div>
</form>
</div>
</div>
<!-- Statistics Cards -->
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="card bg-primary text-white h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h6 class="text-uppercase">Overall Attendance</h6>
<h2 class="mb-0"><?php echo $attendance_percentage; ?>%</h2>
</div>
<div>
<i class="fas fa-chart-pie fa-3x opacity-50"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-success text-white h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h6 class="text-uppercase">Present Days</h6>
<h2 class="mb-0"><?php echo $present_count; ?></h2>
</div>
<div>
<i class="fas fa-check-circle fa-3x opacity-50"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-danger text-white h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h6 class="text-uppercase">Absent Days</h6>
<h2 class="mb-0"><?php echo $absent_count; ?></h2>
</div>
<div>
<i class="fas fa-times-circle fa-3x opacity-50"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-warning text-dark h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h6 class="text-uppercase">Late/Excused Days</h6>
<h2 class="mb-0"><?php echo $late_count + $excused_count; ?></h2>
</div>
<div>
<i class="fas fa-exclamation-circle fa-3x opacity-50"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Charts Section -->
<div class="row mb-4">
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Monthly Attendance Overview</h5>
</div>
<div class="card-body">
<canvas id="monthlyAttendanceChart"></canvas>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Attendance by Course</h5>
</div>
<div class="card-body">
<canvas id="courseAttendanceChart"></canvas>
</div>
</div>
</div>
</div>
<!-- Attendance Records Table -->
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Attendance Records</h5>
</div>
<div class="card-body">
<?php if (empty($attendance_records)): ?>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i> No attendance records found for the selected filters.
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Date</th>
<th>Course</th>
<th>Status</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<?php foreach ($attendance_records as $record): ?>
<tr>
<td><?php echo date('d M Y', strtotime($record['date'])); ?></td>
<td><?php echo htmlspecialchars($record['course_title']); ?></td>
<td>
<span class="badge bg-<?php
echo $record['status'] === 'present' ? 'success' :
($record['status'] === 'absent' ? 'danger' :
($record['status'] === 'late' ? 'warning' : 'info'));
?>">
<?php echo ucfirst($record['status']); ?>
</span>
</td>
<td><?php echo !empty($record['notes']) ? htmlspecialchars($record['notes']) : '-'; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<!-- Include Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Monthly Attendance Chart
const monthlyCtx = document.getElementById('monthlyAttendanceChart').getContext('2d');
const monthlyChart = new Chart(monthlyCtx, {
type: 'bar',
data: {
labels: <?php echo json_encode(array_map(function($date) {
return date('d M', strtotime($date));
}, $dates)); ?>,
datasets: [
{
label: 'Present',
data: <?php echo json_encode($present_data); ?>,
backgroundColor: 'rgba(40, 167, 69, 0.7)',
borderColor: 'rgba(40, 167, 69, 1)',
borderWidth: 1
},
{
label: 'Absent',
data: <?php echo json_encode($absent_data); ?>,
backgroundColor: 'rgba(220, 53, 69, 0.7)',
borderColor: 'rgba(220, 53, 69, 1)',
borderWidth: 1
},
{
label: 'Late',
data: <?php echo json_encode($late_data); ?>,
backgroundColor: 'rgba(255, 193, 7, 0.7)',
borderColor: 'rgba(255, 193, 7, 1)',
borderWidth: 1
},
{
label: 'Excused',
data: <?php echo json_encode($excused_data); ?>,
backgroundColor: 'rgba(23, 162, 184, 0.7)',
borderColor: 'rgba(23, 162, 184, 1)',
borderWidth: 1
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
stacked: true,
},
y: {
stacked: true,
beginAtZero: true,
ticks: {
precision: 0
}
}
}
}
});
// Course Attendance Chart
const courseCtx = document.getElementById('courseAttendanceChart').getContext('2d');
const courseChart = new Chart(courseCtx, {
type: 'doughnut',
data: {
labels: <?php echo json_encode($course_names); ?>,
datasets: [{
data: <?php echo json_encode(array_values($course_attendance_percent)); ?>,
backgroundColor: [
'rgba(78, 115, 223, 0.8)',
'rgba(28, 200, 138, 0.8)',
'rgba(54, 185, 204, 0.8)',
'rgba(246, 194, 62, 0.8)',
'rgba(231, 74, 59, 0.8)',
'rgba(133, 135, 150, 0.8)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return `${context.label}: ${context.raw}% attendance`;
}
}
}
}
}
});
});
</script>
<?php include_once('../includes/student_footer.php'); ?>