<?php
// Add timezone conversion functions at the top of the file
function get_user_timezone() {
// Default to IST (Indian Standard Time)
return 'Asia/Kolkata';
}
function convert_to_user_timezone($datetime_str, $format = 'Y-m-d H:i:s') {
// This is a simplified version that just returns the time in IST format
// since we're defaulting to IST timezone
return date($format, strtotime($datetime_str));
}
// Start session
session_start();
// Include database configuration
require_once '../config/database.php';
// Helper function to remove a query parameter
function remove_query_param($url, $param) {
$parts = parse_url($url);
if (isset($parts['query'])) {
parse_str($parts['query'], $query);
unset($query[$param]);
$parts['query'] = http_build_query($query);
}
return (isset($parts['path']) ? $parts['path'] : '')
. (isset($parts['query']) && !empty($parts['query']) ? '?' . $parts['query'] : '');
}
// Check if user is logged in and has student role
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'student') {
header('Location: ../login.php');
exit;
}
$user_id = $_SESSION['user_id'];
// Get student's enrolled courses
$enrolled_courses_query = "SELECT e.course_id, c.title as course_title
FROM enrollments e
JOIN courses c ON e.course_id = c.id
WHERE e.user_id = ? AND e.status = 'completed'";
$stmt = $conn->prepare($enrolled_courses_query);
$stmt->bind_param("i", $user_id);
$stmt->execute();
$enrolled_result = $stmt->get_result();
$enrolled_courses = [];
while ($row = $enrolled_result->fetch_assoc()) {
$enrolled_courses[] = $row;
}
// Collect all course IDs
$course_ids = [];
foreach ($enrolled_courses as $course) {
$course_ids[] = $course['course_id'];
}
// Filter variables
$filter_course_id = isset($_GET['course_id']) && !empty($_GET['course_id']) ? intval($_GET['course_id']) : null;
$filter_status = isset($_GET['status']) && !empty($_GET['status']) ? $_GET['status'] : null;
$filter_duration = isset($_GET['duration']) && !empty($_GET['duration']) ? $_GET['duration'] : null;
$filter_date_from = isset($_GET['date_from']) && !empty($_GET['date_from']) ? $_GET['date_from'] : null;
$filter_date_to = isset($_GET['date_to']) && !empty($_GET['date_to']) ? $_GET['date_to'] : null;
$filter_search = isset($_GET['search']) && !empty($_GET['search']) ? $_GET['search'] : null;
// Create arrays for different exam types
$upcoming_exams = array();
$ongoing_exams = array();
$past_exams = array();
$exam_results = array();
if (!empty($course_ids)) {
// Build the course filter
$course_filter = "";
if ($filter_course_id !== null && in_array($filter_course_id, $course_ids)) {
$course_filter = " AND es.course_id = " . $filter_course_id;
$course_ids_str = $filter_course_id; // Override course_ids_str for the query
} else {
// Convert array to comma-separated string for IN clause
$course_ids_str = implode(',', $course_ids);
}
// Build the date filter
$date_filter = "";
if ($filter_date_from !== null) {
$date_filter .= " AND es.exam_date >= '" . $conn->real_escape_string($filter_date_from) . "'";
}
if ($filter_date_to !== null) {
$date_filter .= " AND es.exam_date <= '" . $conn->real_escape_string($filter_date_to) . "'";
}
// Build the search filter
$search_filter = "";
if ($filter_search !== null) {
$search_term = $conn->real_escape_string($filter_search);
$search_filter = " AND (es.title LIKE '%{$search_term}%' OR c.title LIKE '%{$search_term}%')";
}
// Current date and time
$today = date('Y-m-d');
$now = date('H:i:s');
$current_datetime = strtotime($today . ' ' . $now);
// Get all exams for enrolled courses
$exams_query = "SELECT es.*, c.title as course_title,
(SELECT COUNT(*) FROM exam_question_maps WHERE exam_id = es.id) as question_count,
(SELECT id FROM student_exams WHERE user_id = ? AND exam_id = es.id) as student_exam_id,
(SELECT status FROM student_exams WHERE user_id = ? AND exam_id = es.id) as exam_status,
(SELECT percentage FROM student_exams WHERE user_id = ? AND exam_id = es.id) as exam_percentage
FROM exam_schedules es
JOIN courses c ON es.course_id = c.id
WHERE es.course_id IN ({$course_ids_str})
AND es.is_active = 1
{$course_filter}
{$date_filter}
{$search_filter}
ORDER BY es.exam_date ASC, es.start_time ASC";
$stmt = $conn->prepare($exams_query);
// Create an array of parameters for binding
$param_types = str_repeat('i', 3); // For the 3 user_id parameters
$params = array_fill(0, 3, $user_id);
// Bind parameters
$stmt->bind_param($param_types, ...$params);
$stmt->execute();
$result = $stmt->get_result();
// Process exams
while ($row = $result->fetch_assoc()) {
// Format dates
$row['date_formatted'] = date('l, F j, Y', strtotime($row['exam_date']));
$row['start_time_formatted'] = date('g:i A', strtotime($row['start_time']));
$row['end_time_formatted'] = date('g:i A', strtotime($row['end_time']));
// Calculate exact duration in minutes
$start_timestamp = strtotime($row['start_time']);
$end_timestamp = strtotime($row['end_time']);
$duration_minutes = round(($end_timestamp - $start_timestamp) / 60);
$row['duration_minutes'] = $duration_minutes;
// Format duration in hours and minutes for display
$hours = floor($duration_minutes / 60);
$minutes = $duration_minutes % 60;
if ($hours > 0) {
$row['duration_formatted'] = $hours . ' hr' . ($hours > 1 ? 's' : '');
if ($minutes > 0) {
$row['duration_formatted'] .= ' ' . $minutes . ' min' . ($minutes > 1 ? 's' : '');
}
} else {
$row['duration_formatted'] = $minutes . ' min' . ($minutes > 1 ? 's' : '');
}
// Set duration color class based on length
if ($duration_minutes < 30) {
$row['duration_class'] = 'success'; // Short exams
} elseif ($duration_minutes <= 60) {
$row['duration_class'] = 'primary'; // Medium exams
} else {
$row['duration_class'] = 'warning'; // Long exams
}
// Calculate full datetime for comparison
$exam_start_datetime = strtotime($row['exam_date'] . ' ' . $row['start_time']);
$exam_end_datetime = strtotime($row['exam_date'] . ' ' . $row['end_time']);
// Categorize exams
if ($exam_end_datetime < $current_datetime) {
// Past exam
$past_exams[] = $row;
// If student has taken the exam, add to results
if (!empty($row['student_exam_id']) && ($row['exam_status'] == 'completed' || $row['exam_status'] == 'graded' || $row['exam_status'] == 'passed' || $row['exam_status'] == 'failed')) {
$exam_results[] = $row;
}
} elseif ($exam_start_datetime <= $current_datetime && $exam_end_datetime >= $current_datetime) {
// Ongoing exam
$ongoing_exams[] = $row;
} else {
// Upcoming exam
$upcoming_exams[] = $row;
}
}
// Apply status filter after categorization
if ($filter_status !== null) {
if ($filter_status === 'upcoming') {
$ongoing_exams = [];
$past_exams = [];
$exam_results = [];
} elseif ($filter_status === 'ongoing') {
$upcoming_exams = [];
$past_exams = [];
$exam_results = [];
} elseif ($filter_status === 'completed') {
$upcoming_exams = [];
$ongoing_exams = [];
$past_exams = array_filter($past_exams, function($exam) {
return empty($exam['student_exam_id']);
});
} elseif ($filter_status === 'pending') {
// Show only the exams that are not started or in progress
$upcoming_exams = array_filter($upcoming_exams, function($exam) {
return empty($exam['student_exam_id']) || $exam['exam_status'] === 'pending';
});
$ongoing_exams = array_filter($ongoing_exams, function($exam) {
return empty($exam['student_exam_id']) || $exam['exam_status'] === 'pending';
});
$past_exams = [];
$exam_results = [];
}
}
// Apply duration filter
if ($filter_duration !== null) {
$duration_filter_function = function($exam) use ($filter_duration) {
if ($filter_duration === 'short') {
return $exam['duration_minutes'] < 30;
} elseif ($filter_duration === 'medium') {
return $exam['duration_minutes'] >= 30 && $exam['duration_minutes'] <= 60;
} elseif ($filter_duration === 'long') {
return $exam['duration_minutes'] > 60;
}
return true;
};
$upcoming_exams = array_filter($upcoming_exams, $duration_filter_function);
$ongoing_exams = array_filter($ongoing_exams, $duration_filter_function);
$past_exams = array_filter($past_exams, $duration_filter_function);
$exam_results = array_filter($exam_results, $duration_filter_function);
}
}
// Include header
$pageTitle = "Exams Dashboard";
include_once 'includes/header.php';
require_once('../includes/functions.php');
?>
<div class="container-fluid">
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">My Exams</h1>
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="collapse" data-bs-target="#filterOptions">
<i class="fas fa-filter"></i> Filter Options
</button>
</div>
<!-- Filter Options -->
<div class="collapse mb-4" id="filterOptions">
<div class="card">
<div class="card-header">
<h6 class="m-0 font-weight-bold text-primary">Filter Exams</h6>
</div>
<div class="card-body">
<form method="GET" action="" id="filterForm" class="row">
<!-- Course Filter -->
<div class="col-md-3 mb-3">
<label for="course_filter">Course</label>
<select class="form-control" id="course_filter" name="course_id">
<option value="">All Courses</option>
<?php foreach ($enrolled_courses as $course): ?>
<option value="<?php echo $course['course_id']; ?>" <?php echo isset($_GET['course_id']) && $_GET['course_id'] == $course['course_id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($course['course_title']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Status Filter -->
<div class="col-md-3 mb-3">
<label for="status_filter">Status</label>
<select class="form-control" id="status_filter" name="status">
<option value="">All Statuses</option>
<option value="upcoming" <?php echo isset($_GET['status']) && $_GET['status'] == 'upcoming' ? 'selected' : ''; ?>>Upcoming</option>
<option value="ongoing" <?php echo isset($_GET['status']) && $_GET['status'] == 'ongoing' ? 'selected' : ''; ?>>Ongoing</option>
<option value="completed" <?php echo isset($_GET['status']) && $_GET['status'] == 'completed' ? 'selected' : ''; ?>>Completed</option>
<option value="pending" <?php echo isset($_GET['status']) && $_GET['status'] == 'pending' ? 'selected' : ''; ?>>Pending</option>
</select>
</div>
<!-- Duration Filter -->
<div class="col-md-3 mb-3">
<label for="duration_filter">Duration</label>
<select class="form-control" id="duration_filter" name="duration">
<option value="">Any Duration</option>
<option value="short" <?php echo isset($_GET['duration']) && $_GET['duration'] == 'short' ? 'selected' : ''; ?>>Short (< 30 mins)</option>
<option value="medium" <?php echo isset($_GET['duration']) && $_GET['duration'] == 'medium' ? 'selected' : ''; ?>>Medium (30-60 mins)</option>
<option value="long" <?php echo isset($_GET['duration']) && $_GET['duration'] == 'long' ? 'selected' : ''; ?>>Long (> 60 mins)</option>
</select>
</div>
<!-- Date Range Filter -->
<div class="col-md-3 mb-3">
<label for="date_from">From Date</label>
<input type="date" class="form-control" id="date_from" name="date_from"
value="<?php echo isset($_GET['date_from']) ? $_GET['date_from'] : ''; ?>">
</div>
<div class="col-md-3 mb-3">
<label for="date_to">To Date</label>
<input type="date" class="form-control" id="date_to" name="date_to"
value="<?php echo isset($_GET['date_to']) ? $_GET['date_to'] : ''; ?>">
</div>
<!-- Search Filter -->
<div class="col-md-9 mb-3">
<label for="search">Search</label>
<input type="text" class="form-control" id="search" name="search" placeholder="Search exam titles..."
value="<?php echo isset($_GET['search']) ? htmlspecialchars($_GET['search']) : ''; ?>">
</div>
<!-- Filter Actions -->
<div class="col-md-3 mb-3 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">
<i class="fas fa-filter"></i> Apply Filters
</button>
<a href="exams.php" class="btn btn-secondary">
<i class="fas fa-undo"></i> Reset
</a>
</div>
</form>
<!-- Duration Legend -->
<div class="mt-3">
<small class="d-block mb-2">Duration Legend:</small>
<div class="d-flex">
<div class="me-3">
<span class="badge bg-success"> </span> Short (< 30 mins)
</div>
<div class="me-3">
<span class="badge bg-primary"> </span> Medium (30-60 mins)
</div>
<div>
<span class="badge bg-warning"> </span> Long (> 60 mins)
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filter Tags - Shows active filters -->
<?php
$active_filters = [];
if ($filter_course_id !== null) {
foreach ($enrolled_courses as $course) {
if ($course['course_id'] == $filter_course_id) {
$active_filters[] = [
'label' => 'Course: ' . htmlspecialchars($course['course_title']),
'param' => 'course_id'
];
break;
}
}
}
if ($filter_status !== null) {
$status_labels = [
'upcoming' => 'Upcoming',
'ongoing' => 'Ongoing',
'completed' => 'Completed',
'pending' => 'Pending'
];
$active_filters[] = [
'label' => 'Status: ' . $status_labels[$filter_status],
'param' => 'status'
];
}
if ($filter_duration !== null) {
$duration_labels = [
'short' => 'Short (< 30 mins)',
'medium' => 'Medium (30-60 mins)',
'long' => 'Long (> 60 mins)'
];
$active_filters[] = [
'label' => 'Duration: ' . $duration_labels[$filter_duration],
'param' => 'duration'
];
}
if ($filter_date_from !== null) {
$active_filters[] = [
'label' => 'From Date: ' . date('M d, Y', strtotime($filter_date_from)),
'param' => 'date_from'
];
}
if ($filter_date_to !== null) {
$active_filters[] = [
'label' => 'To Date: ' . date('M d, Y', strtotime($filter_date_to)),
'param' => 'date_to'
];
}
if ($filter_search !== null) {
$active_filters[] = [
'label' => 'Search: ' . htmlspecialchars($filter_search),
'param' => 'search'
];
}
?>
<?php if (!empty($active_filters)): ?>
<div class="mb-4">
<div class="d-flex flex-wrap">
<?php foreach ($active_filters as $filter): ?>
<div class="badge bg-primary p-2 m-1">
<?php echo $filter['label']; ?>
<a href="<?php echo remove_query_param($_SERVER['REQUEST_URI'], $filter['param']); ?>" class="text-white ms-2">
<i class="fas fa-times"></i>
</a>
</div>
<?php endforeach; ?>
<?php if (count($active_filters) > 1): ?>
<div class="badge bg-danger p-2 m-1">
<a href="exams.php" class="text-white">
Clear All Filters <i class="fas fa-times"></i>
</a>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<!-- Summary of filtered results -->
<?php if (!empty($active_filters)): ?>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Filter Results</h6>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3 text-center mb-3">
<div class="h4 mb-0 font-weight-bold text-primary"><?php echo count($upcoming_exams); ?></div>
<div class="small text-muted">Upcoming Exams</div>
</div>
<div class="col-md-3 text-center mb-3">
<div class="h4 mb-0 font-weight-bold text-warning"><?php echo count($ongoing_exams); ?></div>
<div class="small text-muted">Ongoing Exams</div>
</div>
<div class="col-md-3 text-center mb-3">
<div class="h4 mb-0 font-weight-bold text-success"><?php echo count($exam_results); ?></div>
<div class="small text-muted">Completed Exams</div>
</div>
<div class="col-md-3 text-center mb-3">
<div class="h4 mb-0 font-weight-bold text-secondary"><?php echo count($past_exams); ?></div>
<div class="small text-muted">Past Exams</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['error_message'])): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<?php
echo $_SESSION['error_message'];
unset($_SESSION['error_message']);
?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['success_message'])): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?php
echo $_SESSION['success_message'];
unset($_SESSION['success_message']);
?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if (isset($_GET['completed']) && $_GET['completed'] == 1): ?>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle"></i> You have already completed this exam.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['exam_already_completed'])): ?>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle"></i> You have already completed this exam.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php unset($_SESSION['exam_already_completed']); ?>
<?php endif; ?>
<?php if (empty($enrolled_courses)): ?>
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> You are not enrolled in any courses yet. Please enroll in courses to see available exams.
</div>
<?php else: ?>
<!-- Ongoing Exams -->
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Ongoing Exams</h6>
<span class="badge bg-primary"><?php echo count($ongoing_exams); ?></span>
</div>
<div class="card-body">
<?php if (empty($ongoing_exams)): ?>
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> No exams are currently in progress.
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered" width="100%" cellspacing="0">
<thead>
<tr>
<th>Exam Title</th>
<th>Course</th>
<th>Date</th>
<th>Time</th>
<th>Duration</th>
<th>Questions</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($ongoing_exams as $exam): ?>
<tr>
<td><?php echo htmlspecialchars($exam['title']); ?></td>
<td><?php echo htmlspecialchars($exam['course_title']); ?></td>
<td><?php echo $exam['date_formatted']; ?></td>
<td><?php echo $exam['start_time_formatted'] . ' - ' . $exam['end_time_formatted']; ?></td>
<td>
<div><?php echo $exam['duration_formatted']; ?></div>
<div class="progress mt-1" style="height: 5px;">
<div class="progress-bar bg-<?php echo $exam['duration_class']; ?>" role="progressbar"
style="width: 100%;"
aria-valuenow="100"
aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</td>
<td><?php echo $exam['question_count']; ?></td>
<td>
<?php if ($exam['student_exam_id'] && ($exam['exam_status'] === 'completed' || $exam['exam_status'] === 'graded' || $exam['exam_status'] === 'passed' || $exam['exam_status'] === 'failed')): ?>
<span class="badge bg-success">Completed</span>
<?php elseif ($exam['student_exam_id'] && $exam['exam_status'] === 'in_progress'): ?>
<span class="badge bg-warning text-dark">In Progress</span>
<?php elseif ($exam['student_exam_id'] && $exam['exam_status'] === 'pending'): ?>
<span class="badge bg-info">Ready to Start</span>
<?php else: ?>
<span class="badge bg-success">Available</span>
<?php endif; ?>
</td>
<td>
<?php if ($exam['student_exam_id'] && ($exam['exam_status'] === 'completed' || $exam['exam_status'] === 'graded' || $exam['exam_status'] === 'passed' || $exam['exam_status'] === 'failed')): ?>
<a href="exam_results.php?exam_id=<?php echo $exam['id']; ?>"
class="btn btn-info btn-sm">
<i class="fas fa-eye"></i> View Results
</a>
<?php else: ?>
<a href="take_exam.php?exam_id=<?php echo $exam['id']; ?>"
class="btn btn-primary btn-sm">
<?php if ($exam['student_exam_id'] && $exam['exam_status'] === 'in_progress'): ?>
<i class="fas fa-edit"></i> Continue Exam
<?php elseif ($exam['student_exam_id'] && $exam['exam_status'] === 'pending'): ?>
<i class="fas fa-play"></i> Start Exam
<?php else: ?>
<i class="fas fa-play"></i> Take Exam
<?php endif; ?>
</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<!-- Upcoming Exams -->
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Upcoming Exams</h6>
<span class="badge bg-primary"><?php echo count($upcoming_exams); ?></span>
</div>
<div class="card-body">
<?php if (empty($upcoming_exams)): ?>
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> No upcoming exams scheduled.
</div>
<?php else: ?>
<?php
// Sort exams by date (nearest first)
usort($upcoming_exams, function($a, $b) {
$date_a = strtotime($a['exam_date'] . ' ' . $a['start_time']);
$date_b = strtotime($b['exam_date'] . ' ' . $b['start_time']);
return $date_a - $date_b;
});
// Get the nearest exam
$nearest_exam = $upcoming_exams[0];
$exam_datetime = strtotime($nearest_exam['exam_date'] . ' ' . $nearest_exam['start_time']);
$days_remaining = floor(($exam_datetime - time()) / (60 * 60 * 24));
$hours_remaining = floor(($exam_datetime - time()) / (60 * 60)) % 24;
$minutes_remaining = floor(($exam_datetime - time()) / 60) % 60;
?>
<!-- Nearest Exam Card -->
<div class="row mb-4">
<div class="col-lg-12">
<div class="card bg-light border-left-warning shadow h-100 py-2 mb-4">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-md-8">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
Next Upcoming Exam
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
<?php echo htmlspecialchars($nearest_exam['title']); ?>
</div>
<div class="mb-2">
<span class="text-muted">Course:</span> <?php echo htmlspecialchars($nearest_exam['course_title']); ?>
</div>
<div class="mb-2">
<i class="fas fa-calendar-day text-warning"></i>
<?php echo $nearest_exam['date_formatted']; ?> |
<i class="fas fa-clock text-warning"></i>
<?php echo $nearest_exam['start_time_formatted'] . ' - ' . $nearest_exam['end_time_formatted']; ?>
</div>
<div class="mb-2">
<i class="fas fa-hourglass-half text-warning"></i> Duration: <?php echo $nearest_exam['duration_formatted']; ?>
<div class="progress mt-1" style="height: 5px;">
<div class="progress-bar bg-<?php echo $nearest_exam['duration_class']; ?>" role="progressbar" style="width: 100%;" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
<div class="mb-2">
<i class="fas fa-question-circle text-warning"></i> Questions: <?php echo $nearest_exam['question_count']; ?>
</div>
</div>
<div class="col-md-4 text-center">
<?php
// Convert server time to user timezone for the countdown
$nearest_exam_full_datetime = $nearest_exam['exam_date'] . ' ' . $nearest_exam['start_time'];
$user_full_datetime = convert_to_user_timezone($nearest_exam_full_datetime, 'Y-m-d\TH:i:s');
?>
<div class="countdown-timer mb-2" id="nearest-exam-countdown"
data-date="<?php echo $nearest_exam['exam_date']; ?>"
data-time="<?php echo $nearest_exam['start_time']; ?>"
data-full-date-time="<?php echo $user_full_datetime; ?>">
<div class="h1 font-weight-bold text-warning">
<span id="countdown-days"><?php echo $days_remaining; ?></span>d
<span id="countdown-hours"><?php echo $hours_remaining; ?></span>h
<span id="countdown-minutes"><?php echo $minutes_remaining; ?></span>m
</div>
<div class="text-muted">until exam starts</div>
</div>
<a href="take_exam.php?exam_id=<?php echo $nearest_exam['id']; ?>" class="btn btn-sm btn-warning">
<i class="fas fa-calendar-check"></i> View Exam
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- All Upcoming Exams Table -->
<div class="table-responsive">
<table class="table table-bordered" id="upcomingExamsTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Exam Title</th>
<th>Course</th>
<th>Date</th>
<th>Time</th>
<th>Duration</th>
<th>Questions</th>
<th>Countdown</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($upcoming_exams as $exam):
$exam_datetime = strtotime($exam['exam_date'] . ' ' . $exam['start_time']);
$days_left = floor(($exam_datetime - time()) / (60 * 60 * 24));
$hours_left = floor(($exam_datetime - time()) / (60 * 60)) % 24;
?>
<tr>
<td><?php echo htmlspecialchars($exam['title']); ?></td>
<td><?php echo htmlspecialchars($exam['course_title']); ?></td>
<td><?php echo $exam['date_formatted']; ?></td>
<td><?php echo $exam['start_time_formatted'] . ' - ' . $exam['end_time_formatted']; ?></td>
<td>
<div><?php echo $exam['duration_formatted']; ?></div>
<div class="progress mt-1" style="height: 5px;">
<div class="progress-bar bg-<?php echo $exam['duration_class']; ?>" role="progressbar"
style="width: 100%;"
aria-valuenow="100"
aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</td>
<td><?php echo $exam['question_count']; ?></td>
<td>
<span class="badge bg-warning text-dark">
<?php echo $days_left; ?> days, <?php echo $hours_left; ?> hours
</span>
</td>
<td>
<?php if ($exam['student_exam_id'] && ($exam['exam_status'] === 'completed' || $exam['exam_status'] === 'graded' || $exam['exam_status'] === 'passed' || $exam['exam_status'] === 'failed')): ?>
<a href="exam_results.php?exam_id=<?php echo $exam['id']; ?>" class="btn btn-sm btn-info mb-1">
<i class="fas fa-eye"></i> View Results
</a>
<?php else: ?>
<a href="take_exam.php?exam_id=<?php echo $exam['id']; ?>" class="btn btn-sm btn-warning mb-1">
<i class="fas fa-eye"></i> View
</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<!-- My Results -->
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">My Exam Results</h6>
<span class="badge bg-primary"><?php echo count($exam_results); ?></span>
</div>
<div class="card-body">
<?php if (empty($exam_results)): ?>
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> You haven't completed any exams yet.
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-bordered" id="resultsTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Exam Title</th>
<th>Course</th>
<th>Date</th>
<th>Score</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($exam_results as $result): ?>
<tr>
<td><?php echo htmlspecialchars($result['title']); ?></td>
<td><?php echo htmlspecialchars($result['course_title']); ?></td>
<td><?php echo $result['date_formatted']; ?></td>
<td>
<?php echo number_format($result['exam_percentage'], 1); ?>%
<div class="progress" style="height: 5px;">
<div class="progress-bar bg-<?php echo $result['exam_percentage'] >= $result['passing_percentage'] ? 'success' : 'danger'; ?>"
role="progressbar"
style="width: <?php echo $result['exam_percentage']; ?>%"
aria-valuenow="<?php echo $result['exam_percentage']; ?>"
aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</td>
<td>
<?php
$status_class = '';
switch ($result['exam_status']) {
case 'passed':
$status_class = 'success';
break;
case 'failed':
$status_class = 'danger';
break;
case 'completed':
case 'graded':
$status_class = 'info';
break;
default:
$status_class = 'secondary';
}
?>
<span class="badge bg-<?php echo $status_class; ?>">
<?php echo ucfirst($result['exam_status']); ?>
</span>
</td>
<td>
<a href="exam_results.php?exam_id=<?php echo $result['id']; ?>"
class="btn btn-info btn-sm">
<i class="fas fa-eye"></i> View Results
</a>
<?php
// Check if this exam has a certificate
$cert_query = "SELECT ec.id FROM exam_certificates ec
JOIN student_exams se ON ec.student_exam_id = se.id
WHERE se.user_id = ? AND se.exam_id = ?";
$cert_stmt = $conn->prepare($cert_query);
$cert_stmt->bind_param("ii", $user_id, $result['id']);
$cert_stmt->execute();
$cert_result = $cert_stmt->get_result();
if ($cert_result->num_rows > 0):
$cert = $cert_result->fetch_assoc();
?>
<a href="view_certificate.php?id=<?php echo $cert['id']; ?>"
class="btn btn-success btn-sm ml-1">
<i class="fas fa-certificate"></i> Certificate
</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<!-- Past Exams (Not Taken) -->
<?php if (!empty($past_exams)): ?>
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Past Exams</h6>
<span class="badge bg-primary"><?php echo count($past_exams); ?></span>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="pastExamsTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Exam Title</th>
<th>Course</th>
<th>Date</th>
<th>Time</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<?php foreach ($past_exams as $exam): ?>
<tr>
<td><?php echo htmlspecialchars($exam['title']); ?></td>
<td><?php echo htmlspecialchars($exam['course_title']); ?></td>
<td><?php echo $exam['date_formatted']; ?></td>
<td><?php echo $exam['start_time_formatted'] . ' - ' . $exam['end_time_formatted']; ?></td>
<td><span class="badge bg-secondary">Closed</span></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
<!-- Exam Details Modal -->
<div class="modal fade" id="examDetailsModal" tabindex="-1" aria-labelledby="examDetailsModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="examDetailsModalLabel">Exam Details</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="text-center mb-3">
<h5 id="modal-exam-title" class="font-weight-bold"></h5>
<p id="modal-course-title" class="text-muted"></p>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="card bg-light">
<div class="card-body text-center">
<h6 class="card-title text-primary"><i class="fas fa-calendar-alt"></i> Date</h6>
<p class="card-text" id="modal-exam-date"></p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card bg-light">
<div class="card-body text-center">
<h6 class="card-title text-primary"><i class="fas fa-clock"></i> Time</h6>
<p class="card-text" id="modal-exam-time"></p>
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="card bg-light">
<div class="card-body text-center">
<h6 class="card-title text-primary"><i class="fas fa-hourglass-half"></i> Duration</h6>
<p class="card-text" id="modal-exam-duration"></p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card bg-light">
<div class="card-body text-center">
<h6 class="card-title text-primary"><i class="fas fa-question-circle"></i> Questions</h6>
<p class="card-text" id="modal-exam-questions"></p>
</div>
</div>
</div>
</div>
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> Make sure to join the exam on time. The system may prevent access if you're late.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize DataTables if available
if (typeof $.fn.DataTable !== 'undefined') {
// Initialize DataTables
$('#upcomingExamsTable').DataTable({
"order": [[ 2, "asc" ]], // Sort by date ascending
"dom": 'lrtip', // Remove search box (we have our own filters)
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
});
$('#resultsTable').DataTable({
"order": [[ 2, "desc" ]], // Sort by date descending
"dom": 'lrtip',
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
});
$('#pastExamsTable').DataTable({
"order": [[ 2, "desc" ]], // Sort by date descending
"dom": 'lrtip',
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
});
}
// Auto-open filter panel if filters are applied
if (window.location.search && window.location.search !== '?completed=1') {
document.getElementById('filterOptions').classList.add('show');
}
// Date range validation
const dateFrom = document.getElementById('date_from');
const dateTo = document.getElementById('date_to');
if (dateFrom && dateTo) {
dateFrom.addEventListener('change', function() {
if (dateTo.value && this.value > dateTo.value) {
dateTo.value = this.value;
}
dateTo.min = this.value;
});
dateTo.addEventListener('change', function() {
if (dateFrom.value && this.value < dateFrom.value) {
dateFrom.value = this.value;
}
});
}
// Live countdown for nearest exam
function updateCountdown() {
const countdownEl = document.getElementById('nearest-exam-countdown');
if (!countdownEl) return;
const examDate = countdownEl.dataset.date;
const examTime = countdownEl.dataset.time;
if (!examDate || !examTime) return;
// Get the full datetime string - ISO format for consistent timezone handling
const examDateTime = new Date(countdownEl.dataset.fullDateTime);
const now = new Date();
// Time difference in milliseconds
let diff = examDateTime - now;
// If the exam has passed, stop the countdown
if (diff <= 0) {
document.getElementById('countdown-days').textContent = '0';
document.getElementById('countdown-hours').textContent = '0';
document.getElementById('countdown-minutes').textContent = '0';
return;
}
// Calculate days, hours, minutes
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
diff -= days * (1000 * 60 * 60 * 24);
const hours = Math.floor(diff / (1000 * 60 * 60));
diff -= hours * (1000 * 60 * 60);
const minutes = Math.floor(diff / (1000 * 60));
// Update the countdown elements
document.getElementById('countdown-days').textContent = days;
document.getElementById('countdown-hours').textContent = hours;
document.getElementById('countdown-minutes').textContent = minutes;
}
// Initial update and then update every minute
updateCountdown();
setInterval(updateCountdown, 60000);
// Exam details modal functionality
const examDetailsButtons = document.querySelectorAll('.exam-details-btn');
if (examDetailsButtons.length > 0) {
examDetailsButtons.forEach(button => {
button.addEventListener('click', function() {
const examId = this.dataset.examId;
const examTitle = this.dataset.examTitle;
const courseTitle = this.dataset.courseTitle;
const examDate = this.dataset.examDate;
const startTime = this.dataset.startTime;
const endTime = this.dataset.endTime;
const duration = this.dataset.duration;
const questions = this.dataset.questions;
// Update modal content
document.getElementById('modal-exam-title').textContent = examTitle;
document.getElementById('modal-course-title').textContent = courseTitle;
document.getElementById('modal-exam-date').textContent = examDate;
document.getElementById('modal-exam-time').textContent = `${startTime} - ${endTime}`;
document.getElementById('modal-exam-duration').textContent = duration;
document.getElementById('modal-exam-questions').textContent = `${questions} questions`;
});
});
}
// Live search for table filters
const searchInput = document.getElementById('search');
if (searchInput) {
searchInput.addEventListener('keyup', function(e) {
if (e.key === 'Enter') {
document.getElementById('filterForm').submit();
}
});
}
});
</script>
<?php
// Include footer
include_once 'includes/footer.php';
?>