| Current Path : /home/users/unlimited/www/nigeria.codeskitter.site/admin/ |
| Current File : /home/users/unlimited/www/nigeria.codeskitter.site/admin/dashboard.php |
<?php
include '../includes/config.php';
// Check if user is admin
if(!isset($_SESSION['user_id']) || $_SESSION['user_role'] != 'admin') {
header("Location: login.php");
exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard - eLearning</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css">
<style>
/* Mobile First Styles */
.sidebar {
transition: all 0.3s ease;
}
.stats-card {
min-height: 120px;
}
.stats-card .card-body {
padding: 1rem;
}
.stats-card h2 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
.stats-card h4 {
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.stats-card i {
font-size: 1.5rem !important;
}
/* Mobile Navigation */
.mobile-navbar {
background: #2c3e50;
border-bottom: 1px solid #34495e;
}
.sidebar-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1040;
display: none;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.sidebar {
position: fixed;
top: 0;
left: -280px;
width: 280px;
height: 100vh;
z-index: 1050;
transition: left 0.3s ease;
}
.sidebar.show {
left: 0;
}
.sidebar-backdrop.show {
display: block;
}
.main-content {
margin-left: 0 !important;
}
.stats-card {
margin-bottom: 1rem;
}
.card-body {
padding: 1rem;
}
}
@media (min-width: 768px) and (max-width: 992px) {
.stats-card h2 {
font-size: 1.25rem;
}
.stats-card h4 {
font-size: 0.8rem;
}
.stats-card i {
font-size: 1.25rem !important;
}
}
/* Sidebar styles */
.nav-link {
padding: 0.8rem 1rem;
border-left: 3px solid transparent;
transition: all 0.3s ease;
}
.nav-link:hover,
.nav-link.active {
background: rgba(255,255,255,0.1);
border-left-color: #4e73df;
}
/* Progress bars */
.progress {
height: 6px;
}
/* Card hover effects */
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<!-- Mobile Navigation Bar -->
<nav class="navbar navbar-dark mobile-navbar d-md-none">
<div class="container-fluid">
<button class="navbar-toggler" type="button" id="sidebarToggle">
<span class="navbar-toggler-icon"></span>
</button>
<span class="navbar-brand mb-0 h1">Admin Dashboard</span>
</div>
</nav>
<!-- Sidebar Backdrop -->
<div class="sidebar-backdrop" id="sidebarBackdrop"></div>
<div class="container-fluid">
<div class="row">
<!-- Sidebar -->
<nav id="sidebar" class="col-md-3 col-lg-2 bg-dark sidebar">
<div class="position-sticky pt-3">
<!-- Desktop Header -->
<div class="sidebar-header text-center py-4 d-none d-md-block">
<h4 class="text-white">Admin Panel</h4>
</div>
<!-- Mobile Header -->
<div class="sidebar-header-mobile d-md-none p-3 border-bottom border-secondary">
<div class="d-flex justify-content-between align-items-center">
<h5 class="text-white mb-0">Admin Panel</h5>
<button class="btn-close btn-close-white" id="sidebarClose"></button>
</div>
</div>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active text-white" href="dashboard.php">
<i class="bi bi-speedometer2 me-2"></i>
Dashboard
</a>
</li>
<li class="nav-item">
<a class="nav-link text-white" href="categories.php">
<i class="bi bi-tags me-2"></i>
Categories
</a>
</li>
<li class="nav-item">
<a class="nav-link text-white" href="courses.php">
<i class="bi bi-book me-2"></i>
Courses
</a>
</li>
<li class="nav-item">
<a class="nav-link text-white" href="instructors.php">
<i class="bi bi-people me-2"></i>
Instructors
</a>
</li>
<li class="nav-item">
<a class="nav-link text-white" href="students.php">
<i class="bi bi-person-check me-2"></i>
Students
</a>
</li>
<li class="nav-item mt-4">
<a class="nav-link text-info" href="../index.php" target="_blank">
<i class="bi bi-eye me-2"></i>
View Website
</a>
</li>
<li class="nav-item">
<a class="nav-link text-danger" href="logout.php">
<i class="bi bi-box-arrow-right me-2"></i>
Logout
</a>
</li>
</ul>
</div>
</nav>
<!-- Main content -->
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
<!-- Desktop Header -->
<div class="d-none d-md-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard Overview</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group me-2">
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
</div>
</div>
</div>
<!-- Mobile Header Spacing -->
<div class="d-md-none" style="height: 20px;"></div>
<!-- Stats Cards -->
<div class="row">
<?php
// Get stats data
$course_count = $conn->query("SELECT COUNT(*) as count FROM courses")->fetch_assoc()['count'];
$student_count = $conn->query("SELECT COUNT(*) as count FROM users WHERE role='student'")->fetch_assoc()['count'];
$instructor_count = $conn->query("SELECT COUNT(*) as count FROM instructors")->fetch_assoc()['count'];
$enrollment_count = $conn->query("SELECT COUNT(*) as count FROM enrollments")->fetch_assoc()['count'];
$stats = [
[
'title' => 'Total Courses',
'count' => $course_count,
'icon' => 'bi-book',
'color' => 'primary',
'bg' => 'bg-primary'
],
[
'title' => 'Total Students',
'count' => $student_count,
'icon' => 'bi-people',
'color' => 'success',
'bg' => 'bg-primary'
],
[
'title' => 'Total Instructors',
'count' => $instructor_count,
'icon' => 'bi-person-badge',
'color' => 'warning',
'bg' => 'bg-primary'
],
[
'title' => 'Total Enrollments',
'count' => $enrollment_count,
'icon' => 'bi-cart-check',
'color' => 'info',
'bg' => 'bg-primary'
]
];
foreach ($stats as $stat):
?>
<div class="col-xl-3 col-lg-6 col-md-6 mb-4">
<div class="card text-white <?php echo $stat['bg']; ?> stats-card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div class="flex-grow-1">
<h4 class="card-title fw-normal mb-1"><?php echo $stat['title']; ?></h4>
<h2 class="mb-0 fw-bold"><?php echo $stat['count']; ?></h2>
</div>
<div class="flex-shrink-0">
<i class="bi <?php echo $stat['icon']; ?> fs-2 opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<!-- Recent Activities -->
<div class="row">
<div class="col-xl-6 col-lg-12 mb-4">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Recent Courses</h5>
<a href="courses.php" class="btn btn-sm btn-outline-primary">View All</a>
</div>
<div class="card-body">
<?php
$recent_courses = $conn->query("SELECT * FROM courses ORDER BY created_at DESC LIMIT 5");
if ($recent_courses->num_rows > 0):
while($course = $recent_courses->fetch_assoc()):
// Enhanced image path handling
$image_path = $course['image'];
$display_image = '../assets/images/course-placeholder.jpg';
if (!empty($image_path)) {
$image_path = trim($image_path);
if (preg_match('/^https?:\/\//', $image_path)) {
$display_image = $image_path;
}
elseif (strpos($image_path, '/') === 0) {
$doc_root = $_SERVER['DOCUMENT_ROOT'];
if (strpos($image_path, $doc_root) === 0) {
$display_image = str_replace($doc_root, '', $image_path);
} else {
$display_image = $image_path;
}
}
elseif (strpos($image_path, 'assets/') === 0) {
$display_image = $image_path;
}
else {
$display_image = '../assets/images/courses/' . $image_path;
}
if (strpos($display_image, 'http') !== 0 && !file_exists($display_image)) {
$display_image = '../assets/images/course-placeholder.jpg';
}
}
?>
<div class="d-flex align-items-center mb-3 pb-3 border-bottom">
<img src="<?php echo $display_image; ?>"
alt="<?php echo htmlspecialchars($course['title']); ?>"
class="rounded me-3 flex-shrink-0"
style="width: 50px; height: 50px; object-fit: cover;"
onerror="this.onerror=null; this.src='../assets/images/course-placeholder.jpg';">
<div class="flex-grow-1">
<h6 class="mb-1 text-truncate"><?php echo htmlspecialchars($course['title']); ?></h6>
<small class="text-muted d-block">$<?php echo number_format($course['current_price'], 2); ?></small>
<small class="text-muted"><?php echo date('M j, Y', strtotime($course['created_at'])); ?></small>
</div>
</div>
<?php
endwhile;
else:
echo '<p class="text-muted text-center py-3">No courses found.</p>';
endif;
?>
</div>
</div>
</div>
<div class="col-xl-6 col-lg-12 mb-4">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Student Progress</h5>
<a href="students.php" class="btn btn-sm btn-outline-primary">View All</a>
</div>
<div class="card-body">
<?php
$student_progress = $conn->query("SELECT u.name, e.progress, c.title
FROM enrollments e
JOIN users u ON e.user_id = u.id
JOIN courses c ON e.course_id = c.id
ORDER BY e.enrolled_at DESC LIMIT 5");
if ($student_progress->num_rows > 0):
while($progress = $student_progress->fetch_assoc()):
?>
<div class="mb-3 pb-3 border-bottom">
<div class="d-flex justify-content-between align-items-start mb-1">
<h6 class="mb-0 text-truncate"><?php echo htmlspecialchars($progress['name']); ?></h6>
<span class="badge bg-primary"><?php echo $progress['progress']; ?>%</span>
</div>
<small class="text-muted d-block mb-2"><?php echo htmlspecialchars($progress['title']); ?></small>
<div class="progress" style="height: 6px;">
<div class="progress-bar" role="progressbar" style="width: <?php echo $progress['progress']; ?>%;"></div>
</div>
</div>
<?php
endwhile;
else:
echo '<p class="text-muted text-center py-3">No student progress data.</p>';
endif;
?>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const sidebar = document.getElementById('sidebar');
const sidebarToggle = document.getElementById('sidebarToggle');
const sidebarClose = document.getElementById('sidebarClose');
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
const mainContent = document.querySelector('.main-content');
// Toggle sidebar on mobile
function toggleSidebar() {
if (window.innerWidth < 768) {
sidebar.classList.toggle('show');
sidebarBackdrop.classList.toggle('show');
document.body.style.overflow = sidebar.classList.contains('show') ? 'hidden' : '';
}
}
// Close sidebar
function closeSidebar() {
if (window.innerWidth < 768) {
sidebar.classList.remove('show');
sidebarBackdrop.classList.remove('show');
document.body.style.overflow = '';
}
}
// Event listeners
if (sidebarToggle) {
sidebarToggle.addEventListener('click', toggleSidebar);
}
if (sidebarClose) {
sidebarClose.addEventListener('click', closeSidebar);
}
if (sidebarBackdrop) {
sidebarBackdrop.addEventListener('click', closeSidebar);
}
// Close sidebar when clicking on nav links (mobile)
const navLinks = document.querySelectorAll('#sidebar .nav-link');
navLinks.forEach(link => {
link.addEventListener('click', function() {
if (window.innerWidth < 768) {
closeSidebar();
}
});
});
// Handle window resize
window.addEventListener('resize', function() {
if (window.innerWidth >= 768) {
closeSidebar();
}
});
// Keyboard accessibility - close sidebar with ESC key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && window.innerWidth < 768 && sidebar.classList.contains('show')) {
closeSidebar();
}
});
// Add touch swipe support for mobile
let touchStartX = 0;
let touchEndX = 0;
document.addEventListener('touchstart', function(e) {
touchStartX = e.changedTouches[0].screenX;
});
document.addEventListener('touchend', function(e) {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
function handleSwipe() {
const swipeThreshold = 50;
const swipeDistance = touchEndX - touchStartX;
if (Math.abs(swipeDistance) > swipeThreshold) {
if (swipeDistance > 0 && touchStartX < 50) {
// Swipe right from left edge - open sidebar
if (window.innerWidth < 768 && !sidebar.classList.contains('show')) {
toggleSidebar();
}
} else if (swipeDistance < 0 && sidebar.classList.contains('show')) {
// Swipe left - close sidebar
closeSidebar();
}
}
}
// Add loading animation to stats cards
const statsCards = document.querySelectorAll('.stats-card');
statsCards.forEach((card, index) => {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
setTimeout(() => {
card.style.transition = 'all 0.5s ease';
card.style.opacity = '1';
card.style.transform = 'translateY(0)';
}, index * 100);
});
// Update page title with dynamic data
function updatePageTitle() {
const totalStudents = <?php echo $student_count; ?>;
const totalCourses = <?php echo $course_count; ?>;
document.title = `Dashboard (${totalStudents} Students, ${totalCourses} Courses) - eLearning Admin`;
}
updatePageTitle();
});
</script>
</body>
</html>