<?php
$pageTitle = "Announcements";
include_once('includes/header.php');
// Check if user is logged in
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'student') {
header("Location: ../login.php");
exit();
}
// Get student ID
$student_id = $_SESSION['user_id'];
// Handle marking announcements as read
if (isset($_GET['mark_read']) && is_numeric($_GET['mark_read'])) {
$announcement_id = intval($_GET['mark_read']);
// Check if already read
$check_read = $conn->prepare("SELECT * FROM announcement_reads WHERE announcement_id = ? AND user_id = ?");
$check_read->bind_param("ii", $announcement_id, $student_id);
$check_read->execute();
$already_read = $check_read->get_result()->num_rows > 0;
if (!$already_read) {
// Mark as read
$mark_read = $conn->prepare("INSERT INTO announcement_reads (announcement_id, user_id, read_date) VALUES (?, ?, NOW())");
$mark_read->bind_param("ii", $announcement_id, $student_id);
$mark_read->execute();
// Set success message
$_SESSION['success_message'] = "Announcement marked as read.";
}
// Redirect to refresh the page
header("Location: announcements.php");
exit();
}
// Handle marking all announcements as read
if (isset($_GET['mark_all_read'])) {
// Get all unread announcements for this student
$get_unread = $conn->prepare("
SELECT a.id
FROM announcements a
LEFT JOIN announcement_reads ar ON ar.announcement_id = a.id AND ar.user_id = ?
LEFT JOIN course_enrollments ce ON ce.student_id = ? AND (a.course_id = ce.course_id OR a.course_id IS NULL)
WHERE ar.id IS NULL
AND (a.target_type = 'all' OR (a.target_type = 'course' AND ce.course_id IS NOT NULL))
");
$get_unread->bind_param("ii", $student_id, $student_id);
$get_unread->execute();
$unread_result = $get_unread->get_result();
if ($unread_result->num_rows > 0) {
// Prepare batch insert query
$insert_values = [];
$current_time = date('Y-m-d H:i:s');
while ($row = $unread_result->fetch_assoc()) {
$announcement_id = $row['id'];
// Mark each announcement as read
$mark_read = $conn->prepare("INSERT INTO announcement_reads (announcement_id, user_id, read_date) VALUES (?, ?, NOW())");
$mark_read->bind_param("ii", $announcement_id, $student_id);
$mark_read->execute();
}
// Set success message
$_SESSION['success_message'] = "All announcements marked as read.";
} else {
$_SESSION['info_message'] = "No unread announcements found.";
}
// Redirect to refresh the page
header("Location: announcements.php");
exit();
}
// Check if we need to create the announcement tables
$tableExists = $conn->query("SHOW TABLES LIKE 'announcements'")->num_rows > 0;
if (!$tableExists) {
// Create announcements table
$conn->query("
CREATE TABLE IF NOT EXISTS `announcements` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`content` text NOT NULL,
`created_by` int(11) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime DEFAULT NULL,
`start_date` date DEFAULT NULL,
`end_date` date DEFAULT NULL,
`target_type` enum('all','course','user') NOT NULL DEFAULT 'all',
`course_id` int(11) DEFAULT NULL,
`importance` enum('normal','important','urgent') NOT NULL DEFAULT 'normal',
`status` enum('active','inactive') NOT NULL DEFAULT 'active',
`attachment` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `created_by` (`created_by`),
KEY `course_id` (`course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
");
// Create announcement_reads table
$conn->query("
CREATE TABLE IF NOT EXISTS `announcement_reads` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`announcement_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`read_date` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_read` (`announcement_id`,`user_id`),
KEY `announcement_id` (`announcement_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
");
}
// Get all announcements visible to this student
$query = "
SELECT a.*, u.first_name, u.last_name, c.title as course_title,
(SELECT COUNT(*) FROM announcement_reads ar WHERE ar.announcement_id = a.id AND ar.user_id = ?) as is_read
FROM announcements a
LEFT JOIN users u ON a.created_by = u.id
LEFT JOIN courses c ON a.course_id = c.id
LEFT JOIN enrollments e ON (a.course_id = e.course_id AND e.user_id = ?)
WHERE a.status = 'active'
AND (a.target_type = 'all' OR (a.target_type = 'course' AND e.id IS NOT NULL))
AND (a.end_date IS NULL OR a.end_date >= CURDATE())
ORDER BY a.created_at DESC
";
$stmt = $conn->prepare($query);
$stmt->bind_param("ii", $student_id, $student_id);
$stmt->execute();
$result = $stmt->get_result();
$announcements = [];
while ($row = $result->fetch_assoc()) {
$announcements[] = $row;
}
// Count unread announcements
$unread_count = 0;
foreach ($announcements as $announcement) {
if ($announcement['is_read'] == 0) {
$unread_count++;
}
}
?>
<div class="container py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><?php echo $pageTitle; ?></h2>
<?php if ($unread_count > 0): ?>
<a href="announcements.php?mark_all_read=1" class="btn btn-primary">
<i class="fas fa-check-double me-2"></i> Mark All as Read
</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['info_message'])): ?>
<div class="alert alert-info alert-dismissible fade show" role="alert">
<i class="fas fa-info-circle me-2"></i> <?php echo $_SESSION['info_message']; ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php unset($_SESSION['info_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; ?>
<?php if (empty($announcements)): ?>
<div class="alert alert-info">
<div class="d-flex">
<div class="me-3">
<i class="fas fa-info-circle fa-2x"></i>
</div>
<div>
<h5>No Announcements</h5>
<p class="mb-0">There are no announcements available at this time. Check back later for updates.</p>
</div>
</div>
</div>
<?php else: ?>
<!-- Announcements Filter -->
<div class="card mb-4">
<div class="card-body">
<div class="row align-items-center">
<div class="col-md-3 mb-3 mb-md-0">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="showUnreadOnly">
<label class="form-check-label" for="showUnreadOnly">Show unread only</label>
</div>
</div>
<div class="col-md-9">
<div class="d-flex align-items-center justify-content-md-end">
<div class="me-3">
<select id="announcementFilter" class="form-select form-select-sm">
<option value="all">All Announcements</option>
<option value="course">Course Announcements</option>
<option value="general">General Announcements</option>
<option value="important">Important Announcements</option>
<option value="urgent">Urgent Announcements</option>
</select>
</div>
<div>
<span class="badge bg-primary"><?php echo count($announcements); ?> announcements</span>
<?php if ($unread_count > 0): ?>
<span class="badge bg-danger ms-2"><?php echo $unread_count; ?> unread</span>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Announcements List -->
<div class="announcements-container">
<?php foreach ($announcements as $announcement): ?>
<div class="card mb-3 announcement-card <?php echo $announcement['is_read'] ? 'read' : 'unread'; ?>"
data-importance="<?php echo $announcement['importance']; ?>"
data-type="<?php echo $announcement['target_type'] == 'course' ? 'course' : 'general'; ?>">
<div class="card-header d-flex align-items-center justify-content-between
<?php if ($announcement['importance'] == 'urgent'): ?>bg-danger text-white
<?php elseif ($announcement['importance'] == 'important'): ?>bg-warning
<?php else: ?>bg-light<?php endif; ?>">
<h5 class="mb-0 card-title">
<?php if ($announcement['is_read'] == 0): ?>
<span class="badge bg-primary me-2">New</span>
<?php endif; ?>
<?php echo htmlspecialchars($announcement['title']); ?>
</h5>
<div>
<?php if ($announcement['target_type'] == 'course'): ?>
<span class="badge bg-info me-2">Course</span>
<?php endif; ?>
<?php if ($announcement['is_read'] == 0): ?>
<a href="announcements.php?mark_read=<?php echo $announcement['id']; ?>" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-check"></i> Mark Read
</a>
<?php endif; ?>
</div>
</div>
<div class="card-body">
<div class="mb-3">
<?php echo nl2br(htmlspecialchars($announcement['content'])); ?>
</div>
<?php if (!empty($announcement['attachment'])): ?>
<div class="mb-3">
<a href="../<?php echo htmlspecialchars($announcement['attachment']); ?>" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-paperclip me-2"></i> View Attachment
</a>
</div>
<?php endif; ?>
<div class="d-flex justify-content-between text-muted small">
<div>
<i class="fas fa-user me-1"></i>
<?php echo htmlspecialchars($announcement['first_name'] . ' ' . $announcement['last_name']); ?>
<?php if ($announcement['target_type'] == 'course'): ?>
<span class="mx-2">|</span>
<i class="fas fa-book me-1"></i>
<?php echo htmlspecialchars($announcement['course_title']); ?>
<?php endif; ?>
</div>
<div>
<i class="far fa-calendar-alt me-1"></i>
<?php echo date('M d, Y', strtotime($announcement['created_at'])); ?>
<?php if (!empty($announcement['end_date'])): ?>
<span class="mx-2">|</span>
<i class="fas fa-hourglass-end me-1"></i>
<span title="Expires on">Until <?php echo date('M d, Y', strtotime($announcement['end_date'])); ?></span>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<style>
.announcement-card.unread {
border-left: 4px solid #0d6efd;
}
.announcement-card.read {
opacity: 0.8;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const showUnreadOnlyCheckbox = document.getElementById('showUnreadOnly');
const announcementFilterSelect = document.getElementById('announcementFilter');
const announcementCards = document.querySelectorAll('.announcement-card');
// Function to filter announcements
function filterAnnouncements() {
const showUnreadOnly = showUnreadOnlyCheckbox.checked;
const filterValue = announcementFilterSelect.value;
announcementCards.forEach(card => {
let showCard = true;
// Filter by read status
if (showUnreadOnly && card.classList.contains('read')) {
showCard = false;
}
// Filter by type
if (filterValue !== 'all') {
if (filterValue === 'course' && card.dataset.type !== 'course') {
showCard = false;
} else if (filterValue === 'general' && card.dataset.type !== 'general') {
showCard = false;
} else if (filterValue === 'important' && card.dataset.importance !== 'important') {
showCard = false;
} else if (filterValue === 'urgent' && card.dataset.importance !== 'urgent') {
showCard = false;
}
}
// Show or hide the card
card.style.display = showCard ? 'block' : 'none';
});
// Show message if no results
const visibleCards = document.querySelectorAll('.announcement-card[style="display: block;"]');
const noResultsMsg = document.querySelector('.no-results-message');
if (visibleCards.length === 0 && announcementCards.length > 0) {
// Create no results message if it doesn't exist
if (!noResultsMsg) {
const container = document.querySelector('.announcements-container');
const message = document.createElement('div');
message.className = 'alert alert-info no-results-message';
message.innerHTML = '<i class="fas fa-info-circle me-2"></i> No announcements match your filter criteria.';
container.appendChild(message);
} else {
noResultsMsg.style.display = 'block';
}
} else if (noResultsMsg) {
noResultsMsg.style.display = 'none';
}
}
// Add event listeners
if (showUnreadOnlyCheckbox) {
showUnreadOnlyCheckbox.addEventListener('change', filterAnnouncements);
}
if (announcementFilterSelect) {
announcementFilterSelect.addEventListener('change', filterAnnouncements);
}
});
</script>
<?php include_once('includes/footer.php'); ?>