<?php
// Start the session at the very beginning if not already started
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Process timezone from JavaScript if set - use AJAX method instead of form submission and redirect
if (isset($_POST['timezone']) && !empty($_POST['timezone'])) {
$_SESSION['user_timezone'] = $_POST['timezone'];
// For AJAX requests, just return success and exit
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
echo json_encode(['success' => true]);
exit;
}
// For non-AJAX requests, continue with the page
}
// Improved timezone conversion functions
function get_user_timezone() {
// First check if user has a timezone set in session
if (isset($_SESSION['user_timezone']) && !empty($_SESSION['user_timezone'])) {
return $_SESSION['user_timezone'];
}
// Otherwise default to IST (Indian Standard Time)
return 'Asia/Kolkata';
}
function convert_to_user_timezone($datetime_str, $format = 'Y-m-d H:i:s') {
$user_timezone = get_user_timezone();
$default_timezone = 'Asia/Kolkata'; // Server timezone (IST)
try {
// Create DateTime object in server timezone
$dt = new DateTime($datetime_str, new DateTimeZone($default_timezone));
// If user timezone is different, convert it
if ($user_timezone != $default_timezone) {
$dt->setTimezone(new DateTimeZone($user_timezone));
}
return $dt->format($format);
} catch (Exception $e) {
// Fallback to simple conversion if DateTime fails
return date($format, strtotime($datetime_str));
}
}
$pageTitle = "Scheduled Exams";
include_once('includes/header.php');
require_once('../includes/functions.php');
// Get student ID
$student_id = $_SESSION['user_id'];
// Check if a specific course_id is provided
$course_filter = isset($_GET['course_id']) ? intval($_GET['course_id']) : 0;
// Get current date
$current_date = date('Y-m-d');
// First get courses for which the student has already passed the exams
$passed_courses_query = "
SELECT DISTINCT es.course_id
FROM student_exams se
JOIN exam_schedules es ON se.exam_id = es.id
WHERE se.user_id = ? AND se.status = 'passed'
";
$passed_stmt = $conn->prepare($passed_courses_query);
$passed_stmt->bind_param("i", $student_id);
$passed_stmt->execute();
$passed_result = $passed_stmt->get_result();
$passed_course_ids = [];
while($row = $passed_result->fetch_assoc()) {
$passed_course_ids[] = $row['course_id'];
}
// Prepare the NOT IN clause for SQL
$exclude_courses = "";
if (!empty($passed_course_ids)) {
$exclude_courses = " AND es.course_id NOT IN (" . implode(',', $passed_course_ids) . ")";
}
// Add course filter if specified
$course_filter_clause = $course_filter > 0 ? " AND es.course_id = " . $course_filter : "";
// Get scheduled exams for courses that the student is enrolled in, excluding courses where they passed exams
$query = "
SELECT es.*, c.title as course_title, c.image as course_image,
(SELECT COUNT(*) FROM student_exams se WHERE se.user_id = ? AND se.exam_id = es.id) as attempt_count
FROM exam_schedules es
JOIN courses c ON es.course_id = c.id
JOIN enrollments e ON e.course_id = c.id AND e.user_id = ?
WHERE es.exam_date >= ? AND es.is_active = 1
AND e.status = 'completed'" . $exclude_courses . $course_filter_clause . "
ORDER BY es.exam_date ASC
";
$stmt = $conn->prepare($query);
$stmt->bind_param("iis", $student_id, $student_id, $current_date);
$stmt->execute();
$exams = $stmt->get_result();
// For course filter, also include past exams from that course
if ($course_filter > 0) {
$past_exams_query = "
SELECT es.*, c.title as course_title, c.image as course_image,
se.status as attempt_status, se.percentage as score
FROM exam_schedules es
JOIN courses c ON es.course_id = c.id
JOIN enrollments e ON e.course_id = c.id AND e.user_id = ?
LEFT JOIN student_exams se ON se.exam_id = es.id AND se.user_id = ?
WHERE es.exam_date < ? AND es.is_active = 1
AND e.status = 'completed'
AND es.course_id = ?
ORDER BY es.exam_date DESC
";
$past_stmt = $conn->prepare($past_exams_query);
$past_stmt->bind_param("iisi", $student_id, $student_id, $current_date, $course_filter);
} else {
// Default query for past exams if no course filter is applied
$past_exams_query = "
SELECT es.*, c.title as course_title, c.image as course_image,
se.status as attempt_status, se.percentage as score
FROM exam_schedules es
JOIN courses c ON es.course_id = c.id
JOIN enrollments e ON e.course_id = c.id AND e.user_id = ?
LEFT JOIN student_exams se ON se.exam_id = es.id AND se.user_id = ?
WHERE es.exam_date < ? AND es.is_active = 1
AND e.status = 'completed'
ORDER BY es.exam_date DESC
LIMIT 3
";
$past_stmt = $conn->prepare($past_exams_query);
$past_stmt->bind_param("iis", $student_id, $student_id, $current_date);
}
$past_stmt->execute();
$past_exams = $past_stmt->get_result();
// Get course details if a specific course is filtered
$course_details = null;
if ($course_filter > 0) {
$course_query = "
SELECT c.*
FROM courses c
WHERE c.id = ?
";
$course_stmt = $conn->prepare($course_query);
$course_stmt->bind_param("i", $course_filter);
$course_stmt->execute();
$course_result = $course_stmt->get_result();
if ($course_result->num_rows > 0) {
$course_details = $course_result->fetch_assoc();
}
}
?>
<div class="container py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><?php echo $course_details ? "Exams: " . htmlspecialchars($course_details['title']) : $pageTitle; ?></h2>
<?php if ($course_filter > 0): ?>
<div>
<a href="scheduled-exams.php" class="btn btn-outline-primary me-2">
<i class="fas fa-list me-2"></i>View All Exams
</a>
<a href="my_courses.php" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-2"></i>Back to My Courses
</a>
</div>
<?php else: ?>
<a href="previous-exams.php" class="btn btn-outline-primary">
<i class="fas fa-history me-2"></i>View All Previous Exams
</a>
<?php endif; ?>
</div>
<?php if (isset($_SESSION['success_message'])): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle me-2"></i> <?php echo $_SESSION['success_message']; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php unset($_SESSION['success_message']); endif; ?>
<?php if (isset($_SESSION['error_message'])): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle me-2"></i> <?php echo $_SESSION['error_message']; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php unset($_SESSION['error_message']); endif; ?>
<!-- Information Card -->
<div class="card mb-4">
<div class="card-body bg-light">
<div class="d-flex">
<div class="me-3">
<i class="fas fa-info-circle text-primary fa-2x"></i>
</div>
<div>
<h5>Important Information About Exams</h5>
<p class="mb-0">Please read the exam instructions carefully before starting. Make sure you have a stable internet connection. Once you start an exam, the timer will begin and cannot be paused. If you pass an exam, you'll be able to generate a certificate. Good luck!</p>
</div>
</div>
</div>
</div>
<?php if ($course_details): ?>
<!-- Course Information -->
<div class="card mb-4">
<div class="card-header bg-secondary text-white">
<h5 class="mb-0"><i class="fas fa-book me-2"></i>Course Information</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3">
<img src="<?php echo !empty($course_details['image']) ? '../' . $course_details['image'] : '../assets/img/course-placeholder.jpg'; ?>"
class="img-fluid rounded" alt="<?php echo htmlspecialchars($course_details['title']); ?>">
</div>
<div class="col-md-9">
<h4><?php echo htmlspecialchars($course_details['title']); ?></h4>
<p><?php echo htmlspecialchars(substr($course_details['description'], 0, 300)) . (strlen($course_details['description']) > 300 ? '...' : ''); ?></p>
<a href="course_details.php?id=<?php echo $course_details['id']; ?>" class="btn btn-outline-primary btn-sm">
<i class="fas fa-info-circle me-1"></i> View Course Details
</a>
</div>
</div>
</div>
</div>
<?php endif; ?>
<!-- Upcoming Exams -->
<div class="card mb-4">
<div class="card-header bg-primary text-white">
<h5 class="mb-0"><i class="fas fa-calendar-alt me-2"></i>Upcoming Exams</h5>
</div>
<div class="card-body">
<?php if ($exams->num_rows > 0): ?>
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>Exam</th>
<th>Course</th>
<th>Date & Time</th>
<th>Duration</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php while ($exam = $exams->fetch_assoc()): ?>
<tr>
<td>
<strong><?php echo htmlspecialchars($exam['title']); ?></strong>
</td>
<td><?php echo htmlspecialchars($exam['course_title']); ?></td>
<td>
<i class="far fa-calendar-alt me-1"></i> <?php echo date('d M Y', strtotime($exam['exam_date'])); ?><br>
<i class="far fa-clock me-1"></i>
<?php
// Show both IST and user local time
$ist_start = date('h:i A', strtotime($exam['start_time']));
$ist_end = date('h:i A', strtotime($exam['end_time']));
// Convert to user timezone
$exam_full_datetime = $exam['exam_date'] . ' ' . $exam['start_time'];
$user_datetime_iso = convert_to_user_timezone($exam_full_datetime, 'Y-m-d\TH:i:s');
$user_start = convert_to_user_timezone($exam_full_datetime, 'h:i A');
$user_end = convert_to_user_timezone($exam['exam_date'] . ' ' . $exam['end_time'], 'h:i A');
$user_tz = get_user_timezone();
if ($user_tz == 'Asia/Kolkata') {
// User is already in IST timezone
echo "$ist_start - $ist_end (IST)";
} else {
// Show both IST and local time
echo "$ist_start - $ist_end (IST)<br>";
echo "<i class='far fa-clock me-1'></i> $user_start - $user_end (Your local time)";
}
?>
</td>
<td><?php echo $exam['duration_minutes']; ?> minutes</td>
<td>
<?php
// Use server time (IST) for determining if exam can be taken
$exam_datetime = $exam['exam_date'] . ' ' . $exam['start_time'];
$end_datetime = date('Y-m-d H:i:s', strtotime($exam['exam_date'] . ' ' . $exam['end_time']));
$current_datetime = date('Y-m-d H:i:s');
if ($current_datetime < $exam_datetime): ?>
<span class="badge bg-warning">Upcoming</span>
<div class="mt-1">
<small><strong>Starts in: </strong>
<span data-countdown="<?php echo $user_datetime_iso; ?>"
data-exam-id="<?php echo $exam['id']; ?>"
class="countdown-timer">
Calculating...
</span>
</small>
</div>
<?php else:
if ($current_datetime <= $end_datetime): ?>
<span class="badge bg-success">In Progress</span>
<?php else: ?>
<span class="badge bg-danger">Closed</span>
<?php endif; ?>
<?php endif; ?>
<?php if ($exam['attempt_count'] > 0): ?>
<span class="badge bg-info ms-1">Attempted</span>
<?php endif; ?>
</td>
<td>
<?php
$can_take_exam = false;
$disabled = '';
$message = '';
// Use server time (IST) for determining if exam can be taken
$exam_datetime = $exam['exam_date'] . ' ' . $exam['start_time'];
$end_datetime = date('Y-m-d H:i:s', strtotime($exam['exam_date'] . ' ' . $exam['end_time']));
$current_datetime = date('Y-m-d H:i:s');
if ($current_datetime < $exam_datetime) {
$disabled = 'disabled';
$message = 'Exam has not started yet';
} else if ($current_datetime > $end_datetime) {
$disabled = 'disabled';
$message = 'Exam has ended';
} else if ($exam['attempt_count'] >= $exam['attempts_allowed'] && $exam['attempts_allowed'] > 0) {
$disabled = 'disabled';
$message = 'Maximum attempts reached';
} else {
$can_take_exam = true;
}
?>
<?php if ($can_take_exam): ?>
<a href="take_exam.php?id=<?php echo $exam['id']; ?>" class="btn btn-sm btn-primary">
<i class="fas fa-edit me-1"></i> Take Exam
</a>
<?php else: ?>
<button class="btn btn-sm btn-secondary" <?php echo $disabled; ?> data-bs-toggle="tooltip" title="<?php echo $message; ?>">
<i class="fas fa-edit me-1"></i> Take Exam
</button>
<?php endif; ?>
<a href="exam_details.php?id=<?php echo $exam['id']; ?>" class="btn btn-sm btn-outline-info ms-1">
<i class="fas fa-info-circle"></i>
</a>
</td>
</tr>
<?php endwhile; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
<?php if ($course_filter > 0): ?>
No upcoming exams scheduled for this course, or you have already passed all available exams.
<?php else: ?>
No upcoming exams scheduled for your enrolled courses, or you have already passed all available exams.
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<!-- Recent Exams -->
<div class="card">
<div class="card-header bg-secondary text-white">
<h5 class="mb-0"><i class="fas fa-history me-2"></i>Recent Exams</h5>
</div>
<div class="card-body">
<?php if ($past_exams->num_rows > 0): ?>
<div class="row">
<?php while ($past_exam = $past_exams->fetch_assoc()): ?>
<div class="col-md-4 mb-3">
<div class="card h-100">
<div class="card-header">
<h6 class="mb-0"><?php echo htmlspecialchars($past_exam['title']); ?></h6>
</div>
<div class="card-body">
<p class="mb-1"><strong>Course:</strong> <?php echo htmlspecialchars($past_exam['course_title']); ?></p>
<p class="mb-1"><strong>Date:</strong> <?php echo date('d M Y', strtotime($past_exam['exam_date'])); ?></p>
<p class="mb-1"><strong>Duration:</strong> <?php echo $past_exam['duration_minutes']; ?> minutes</p>
<?php if ($past_exam['attempt_status']): ?>
<p class="mb-1"><strong>Status:</strong>
<?php if ($past_exam['attempt_status'] == 'passed'): ?>
<span class="text-success">Passed</span>
<?php elseif ($past_exam['attempt_status'] == 'failed'): ?>
<span class="text-danger">Failed</span>
<?php else: ?>
<span class="text-warning"><?php echo ucfirst($past_exam['attempt_status']); ?></span>
<?php endif; ?>
</p>
<p class="mb-3"><strong>Score:</strong>
<?php if ($past_exam['score']): ?>
<?php echo $past_exam['score']; ?>%
<?php else: ?>
N/A
<?php endif; ?>
</p>
<a href="exam-results.php?id=<?php echo $past_exam['id']; ?>" class="btn btn-sm btn-primary">View Results</a>
<?php else: ?>
<p class="mb-3"><strong>Status:</strong> <span class="text-secondary">Not Attempted</span></p>
<?php endif; ?>
</div>
</div>
</div>
<?php endwhile; ?>
</div>
<div class="text-center mt-3">
<a href="previous-exams.php<?php echo $course_filter > 0 ? '?course_id='.$course_filter : ''; ?>" class="btn btn-outline-secondary">
<i class="fas fa-history me-2"></i>View All Previous Exams
</a>
</div>
<?php else: ?>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i> No previous exam records found.
</div>
<?php endif; ?>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
});
// Detect user's timezone and send to server if not already set
function detectUserTimezone() {
// Check if we've already set a timezone in this session - prevents unnecessary submissions
const currentTimezone = '<?php echo isset($_SESSION["user_timezone"]) ? $_SESSION["user_timezone"] : ""; ?>';
if (!sessionStorage.getItem('timezone_sent') && !currentTimezone) {
try {
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (timezone) {
// Set flag so we don't keep sending on every page load
sessionStorage.setItem('timezone_sent', 'true');
// Use fetch API to send timezone to server
fetch(window.location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: 'timezone=' + encodeURIComponent(timezone)
})
.then(response => response.json())
.then(data => {
if (data.success) {
console.log('Timezone set successfully:', timezone);
}
})
.catch(error => {
console.error('Error setting timezone:', error);
});
}
} catch (e) {
console.error('Error detecting timezone:', e);
}
}
}
// Run timezone detection
detectUserTimezone();
// Add countdown timer for upcoming exams
function updateExamCountdowns() {
document.querySelectorAll('[data-countdown]').forEach(function(element) {
const examDateTime = new Date(element.dataset.countdown);
const now = new Date();
const diff = examDateTime - now;
if (diff <= 0) {
element.innerHTML = 'Exam has started!';
// Only reload once if needed and not within last minute
if (diff > -60000 && !sessionStorage.getItem('exam_started_' + element.dataset.examId)) {
sessionStorage.setItem('exam_started_' + element.dataset.examId, 'true');
// Give a short delay before reload
setTimeout(function() {
window.location.reload();
}, 2000);
}
return;
}
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
let countdownText = '';
if (days > 0) {
countdownText += days + 'd ';
}
countdownText += hours + 'h ' + minutes + 'm ' + seconds + 's';
element.innerHTML = countdownText;
});
}
// Start countdown timers if they exist
if (document.querySelector('[data-countdown]')) {
updateExamCountdowns();
setInterval(updateExamCountdowns, 1000);
}
});
</script>
<?php include_once('includes/footer.php'); ?>