V1rus Private
User / IP
:
216.73.217.108
Host / Server
:
190.92.174.125 / aerosofthealthcare.com
System
:
Linux s3739.bom1.stableserver.net 4.18.0-513.24.1.lve.2.el8.x86_64 #1 SMP Fri May 24 12:42:50 UTC 2024 x86_64
Cmd
|
Upload
|
Mass Deface
|
Create
|
Sym
:
/
home
/
aerosoft
/
public_html
/
exam
/
Viewing: admin_dashboard.php
<?php include 'config.php'; if (!isset($_SESSION['admin_id'])) { header("Location: login.php"); exit(); } // Calculate statistics for dashboard try { // Total Students $stmt = $pdo->query("SELECT COUNT(*) as total FROM students"); $totalStudents = $stmt->fetch()['total']; // Total Certificates $stmt = $pdo->query("SELECT COUNT(*) as total FROM certificates"); $totalCerts = $stmt->fetch()['total']; // Total Categories $stmt = $pdo->query("SELECT COUNT(*) as total FROM categories"); $totalCats = $stmt->fetch()['total']; // Total Questions $stmt = $pdo->query("SELECT COUNT(*) as total FROM questions"); $totalQuestions = $stmt->fetch()['total']; // Success Rate $stmt = $pdo->query("SELECT COUNT(*) as total FROM exams"); $totalExams = $stmt->fetch()['total']; $stmt = $pdo->query("SELECT COUNT(*) as passed FROM exams WHERE status = 'passed'"); $passedExams = $stmt->fetch()['passed']; $successRate = $totalExams > 0 ? round(($passedExams / $totalExams) * 100) : 0; // Recent Activity Count $stmt = $pdo->query("SELECT COUNT(*) as pending FROM exams WHERE status = 'pending'"); $pendingActions = $stmt->fetch()['pending']; // Get real category distribution for chart $categoryStmt = $pdo->query("SELECT c.name, COUNT(q.id) as question_count FROM categories c LEFT JOIN questions q ON c.id = q.category_id GROUP BY c.id, c.name"); $categoryData = $categoryStmt->fetchAll(); // Get exam results for display $examStmt = $pdo->query("SELECT e.*, s.name as student_name, c.name as category_name FROM exams e JOIN students s ON e.student_id = s.id JOIN categories c ON e.category_id = c.id ORDER BY e.completed_at DESC LIMIT 8"); $recentExams = $examStmt->fetchAll(); } catch(PDOException $e) { // Initialize variables to avoid undefined errors $totalStudents = 0; $totalCerts = 0; $totalCats = 0; $totalQuestions = 0; $successRate = 0; $pendingActions = 0; $categoryData = []; $recentExams = []; error_log("Database error: " . $e->getMessage()); } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Admin Dashboard | LearnHub</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link href="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet"> <style> :root { --primary-color: #4361ee; --secondary-color: #3a0ca3; --accent-color: #4cc9f0; --success-color: #4bb543; --warning-color: #f6c23e; --danger-color: #e74a3b; --dark-color: #2d3748; --light-color: #f8f9fa; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; margin: 0; padding: 0; } .dashboard-container { background: rgba(255, 255, 255, 0.95); border-radius: 20px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); margin: 20px; overflow: hidden; } .sidebar { background: linear-gradient(135deg, var(--secondary-color), var(--primary-color)); color: white; min-height: 100vh; padding: 0; } .sidebar-header { padding: 30px 20px; text-align: center; background: rgba(0, 0, 0, 0.1); border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .sidebar .nav-link { color: rgba(255, 255, 255, 0.8); padding: 15px 25px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); transition: all 0.3s ease; position: relative; overflow: hidden; text-decoration: none; } .sidebar .nav-link::before { content: ''; position: absolute; left: -100%; top: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.1); transition: left 0.3s ease; } .sidebar .nav-link:hover::before, .sidebar .nav-link.active::before { left: 0; } .sidebar .nav-link:hover, .sidebar .nav-link.active { color: white; background: rgba(255, 255, 255, 0.1); padding-left: 30px; } .sidebar .nav-link i { width: 25px; margin-right: 10px; font-size: 1.1em; } .main-content { background: var(--light-color); min-height: 100vh; padding: 0; } .top-navbar { background: white; padding: 15px 30px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); border-bottom: 1px solid #e3e6f0; } .dashboard-card { border: none; border-radius: 15px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); transition: all 0.3s ease; overflow: hidden; } .dashboard-card:hover { transform: translateY(-8px); box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15); } .stat-card { border-left: 5px solid; position: relative; overflow: hidden; } .stat-card::before { content: ''; position: absolute; top: -50%; right: -50%; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.1); transform: rotate(30deg); } .stat-card.students { border-left-color: var(--primary-color); } .stat-card.certificates { border-left-color: var(--success-color); } .stat-card.success-rate { border-left-color: var(--accent-color); } .stat-card.pending { border-left-color: var(--warning-color); } .chart-container { background: white; border-radius: 15px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); padding: 25px; margin-bottom: 25px; border: 1px solid #e3e6f0; position: relative; } .chart-wrapper { position: relative; height: 300px; width: 100%; } .table-container { background: white; border-radius: 15px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); padding: 25px; margin-bottom: 25px; border: 1px solid #e3e6f0; } .btn-primary { background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); border: none; border-radius: 10px; padding: 10px 20px; font-weight: 600; transition: all 0.3s ease; } .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(67, 97, 238, 0.4); color: white; } .badge { border-radius: 8px; padding: 6px 12px; font-weight: 600; } .action-buttons .btn { margin: 2px; border-radius: 8px; transition: all 0.3s ease; } .action-buttons .btn:hover { transform: scale(1.1); } .nav-tabs .nav-link { border: none; border-bottom: 3px solid transparent; color: var(--dark-color); font-weight: 600; padding: 12px 25px; transition: all 0.3s ease; } .nav-tabs .nav-link.active { background: none; border-bottom: 3px solid var(--primary-color); color: var(--primary-color); } .feature-highlight { background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 30px; border-radius: 15px; margin: 20px 0; text-align: center; } .quick-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0; } .quick-stat-item { background: white; padding: 20px; border-radius: 10px; text-align: center; box-shadow: 0 2px 10px rgba(0,0,0,0.1); transition: all 0.3s ease; } .quick-stat-item:hover { transform: translateY(-5px); box-shadow: 0 5px 20px rgba(0,0,0,0.15); } .import-section { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 25px; border-radius: 15px; margin: 20px 0; } @media (max-width: 768px) { .dashboard-container { margin: 10px; border-radius: 15px; } .sidebar { min-height: auto; } .main-content { padding: 15px; } .chart-wrapper { height: 250px; } } .progress { height: 8px; border-radius: 10px; } .notification-badge { position: absolute; top: 10px; right: 10px; background: var(--danger-color); color: white; border-radius: 50%; width: 20px; height: 20px; font-size: 0.7rem; display: flex; align-items: center; justify-content: center; } .file-upload-area { border: 2px dashed #dee2e6; border-radius: 10px; padding: 40px 20px; text-align: center; background: #f8f9fa; transition: all 0.3s ease; cursor: pointer; } .file-upload-area:hover { border-color: var(--primary-color); background: #e9ecef; } .file-upload-area.dragover { border-color: var(--primary-color); background: var(--primary-color); color: white; } .tab-content { display: none; } .tab-content.active { display: block; } .avatar { width: 35px; height: 35px; display: flex; align-items: center; justify-content: center; font-weight: bold; border-radius: 50%; } .category-icon { width: 35px; height: 35px; display: flex; align-items: center; justify-content: center; border-radius: 50%; } </style> </head> <body> <div class="container-fluid dashboard-container"> <div class="row"> <!-- Enhanced Sidebar --> <div class="col-md-3 col-lg-2 sidebar"> <div class="sidebar-header"> <h4 class="mb-0"> <i class="fas fa-graduation-cap"></i> LearnHub </h4> <small class="text-white-50">Admin Panel</small> </div> <div class="sidebar-sticky pt-3"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="javascript:void(0)" onclick="showTab('dashboard')"> <i class="fas fa-tachometer-alt"></i> Dashboard </a> </li> <li class="nav-item"> <a class="nav-link" href="javascript:void(0)" onclick="showTab('categories')"> <i class="fas fa-layer-group"></i> Categories <span class="badge bg-light text-dark ms-2"><?php echo $totalCats; ?></span> </a> </li> <li class="nav-item"> <a class="nav-link" href="javascript:void(0)" onclick="showTab('questions')"> <i class="fas fa-question-circle"></i> Questions <span class="badge bg-light text-dark ms-2"><?php echo $totalQuestions; ?></span> </a> </li> <li class="nav-item"> <a class="nav-link" href="javascript:void(0)" onclick="showTab('students')"> <i class="fas fa-users"></i> Students <span class="badge bg-light text-dark ms-2"><?php echo $totalStudents; ?></span> </a> </li> <li class="nav-item"> <a class="nav-link" href="javascript:void(0)" onclick="showTab('certificates')"> <i class="fas fa-certificate"></i> Certificates <span class="badge bg-light text-dark ms-2"><?php echo $totalCerts; ?></span> </a> </li> <li class="nav-item"> <a class="nav-link" href="javascript:void(0)" onclick="showTab('exams')"> <i class="fas fa-clipboard-list"></i> Exam Results <span class="badge bg-light text-dark ms-2"><?php echo $totalExams; ?></span> </a> </li> <li class="nav-item"> <a class="nav-link" href="javascript:void(0)" onclick="showTab('import')"> <i class="fas fa-file-import"></i> Bulk Import </a> </li> <li class="nav-item mt-4"> <a class="nav-link" href="logout.php"> <i class="fas fa-sign-out-alt"></i> Logout </a> </li> </ul> </div> </div> <!-- Main Content --> <div class="col-md-9 col-lg-10 main-content"> <!-- Top Navigation --> <div class="top-navbar"> <div class="row align-items-center"> <div class="col-md-6"> <h3 class="mb-0 text-dark" id="currentTabTitle">Dashboard Overview</h3> </div> <div class="col-md-6 text-end"> <span class="text-muted me-3"> <i class="fas fa-user-shield me-1"></i> <?php echo $_SESSION['admin_username']; ?> </span> <div class="btn-group"> <button class="btn btn-outline-primary btn-sm"> <i class="fas fa-cog"></i> </button> <button class="btn btn-outline-primary btn-sm"> <i class="fas fa-bell"></i> <span class="notification-badge">3</span> </button> </div> </div> </div> </div> <div class="p-4"> <!-- Dashboard Tab --> <div id="dashboard-tab" class="tab-content active"> <!-- Quick Stats --> <div class="quick-stats"> <div class="quick-stat-item"> <i class="fas fa-users fa-2x text-primary mb-2"></i> <h5 class="mb-1"><?php echo $totalStudents; ?></h5> <small class="text-muted">Total Students</small> </div> <div class="quick-stat-item"> <i class="fas fa-certificate fa-2x text-success mb-2"></i> <h5 class="mb-1"><?php echo $totalCerts; ?></h5> <small class="text-muted">Certificates</small> </div> <div class="quick-stat-item"> <i class="fas fa-check-circle fa-2x text-info mb-2"></i> <h5 class="mb-1"><?php echo $successRate; ?>%</h5> <small class="text-muted">Success Rate</small> </div> <div class="quick-stat-item"> <i class="fas fa-tasks fa-2x text-warning mb-2"></i> <h5 class="mb-1"><?php echo $pendingActions; ?></h5> <small class="text-muted">Pending Actions</small> </div> </div> <!-- Main Statistics Cards --> <div class="row mb-4"> <div class="col-xl-3 col-md-6 mb-4"> <div class="card dashboard-card stat-card students h-100"> <div class="card-body"> <div class="d-flex justify-content-between"> <div> <h6 class="card-title text-muted mb-2">Total Students</h6> <h3 class="font-weight-bold text-primary"><?php echo $totalStudents; ?></h3> <small class="text-success"> <i class="fas fa-arrow-up"></i> 12% increase </small> </div> <div class="align-self-center"> <i class="fas fa-users fa-3x text-primary opacity-25"></i> </div> </div> </div> </div> </div> <div class="col-xl-3 col-md-6 mb-4"> <div class="card dashboard-card stat-card certificates h-100"> <div class="card-body"> <div class="d-flex justify-content-between"> <div> <h6 class="card-title text-muted mb-2">Certificates Issued</h6> <h3 class="font-weight-bold text-success"><?php echo $totalCerts; ?></h3> <small class="text-success"> <i class="fas fa-arrow-up"></i> 8% increase </small> </div> <div class="align-self-center"> <i class="fas fa-certificate fa-3x text-success opacity-25"></i> </div> </div> </div> </div> </div> <div class="col-xl-3 col-md-6 mb-4"> <div class="card dashboard-card stat-card success-rate h-100"> <div class="card-body"> <div class="d-flex justify-content-between"> <div> <h6 class="card-title text-muted mb-2">Success Rate</h6> <h3 class="font-weight-bold text-info"><?php echo $successRate; ?>%</h3> <div class="progress mt-2" style="height: 6px;"> <div class="progress-bar bg-info" style="width: <?php echo $successRate; ?>%"></div> </div> </div> <div class="align-self-center"> <i class="fas fa-chart-line fa-3x text-info opacity-25"></i> </div> </div> </div> </div> </div> <div class="col-xl-3 col-md-6 mb-4"> <div class="card dashboard-card stat-card pending h-100"> <div class="card-body"> <div class="d-flex justify-content-between"> <div> <h6 class="card-title text-muted mb-2">Pending Actions</h6> <h3 class="font-weight-bold text-warning"><?php echo $pendingActions; ?></h3> <small class="text-warning">Requires attention</small> </div> <div class="align-self-center"> <i class="fas fa-tasks fa-3x text-warning opacity-25"></i> </div> </div> </div> </div> </div> </div> <!-- Charts Row --> <div class="row"> <div class="col-xl-8 col-lg-7"> <div class="chart-container"> <h5 class="mb-3"> <i class="fas fa-chart-bar me-2"></i>Exam Performance Overview </h5> <div class="chart-wrapper"> <canvas id="performanceChart"></canvas> </div> </div> </div> <div class="col-xl-4 col-lg-5"> <div class="chart-container"> <h5 class="mb-3"> <i class="fas fa-chart-pie me-2"></i>Category Distribution </h5> <div class="chart-wrapper"> <canvas id="categoryChart"></canvas> </div> </div> </div> </div> <!-- Recent Activity --> <div class="row mt-4"> <div class="col-12"> <div class="table-container"> <h5 class="mb-3"> <i class="fas fa-history me-2"></i>Recent Exam Activity </h5> <div class="table-responsive"> <table class="table table-hover"> <thead class="table-light"> <tr> <th>Student</th> <th>Exam</th> <th>Score</th> <th>Status</th> <th>Date</th> <th>Actions</th> </tr> </thead> <tbody> <?php if (!empty($recentExams)): ?> <?php foreach ($recentExams as $activity): ?> <?php $statusClass = $activity['status'] == 'passed' ? 'success' : ($activity['status'] == 'failed' ? 'danger' : 'warning'); ?> <tr> <td> <div class="d-flex align-items-center"> <div class="avatar bg-primary text-white rounded-circle me-2"> <?php echo strtoupper(substr($activity['student_name'], 0, 1)); ?> </div> <?php echo htmlspecialchars($activity['student_name']); ?> </div> </td> <td><?php echo htmlspecialchars($activity['category_name']); ?></td> <td> <div class="progress" style="height: 8px; width: 80px;"> <div class="progress-bar bg-<?php echo $statusClass; ?>" style="width: <?php echo $activity['percentage']; ?>%"></div> </div> <small><?php echo $activity['percentage']; ?>%</small> </td> <td><span class="badge bg-<?php echo $statusClass; ?>"><?php echo ucfirst($activity['status']); ?></span></td> <td><?php echo date('M j, Y', strtotime($activity['completed_at'])); ?></td> <td class="action-buttons"> <button class="btn btn-sm btn-info view-result" data-id="<?php echo $activity['id']; ?>" title="View Details"> <i class="fas fa-eye"></i> </button> <?php if ($activity['status'] == 'passed'): ?> <button class="btn btn-sm btn-success generate-certificate" data-id="<?php echo $activity['id']; ?>" title="Generate Certificate"> <i class="fas fa-certificate"></i> </button> <?php endif; ?> </td> </tr> <?php endforeach; ?> <?php else: ?> <tr> <td colspan="6" class="text-center text-danger py-4"> <i class="fas fa-exclamation-triangle me-2"></i> No recent exam activity found </td> </tr> <?php endif; ?> </tbody> </table> </div> </div> </div> </div> </div> <!-- Categories Management Tab --> <div id="categories-tab" class="tab-content"> <div class="d-flex justify-content-between align-items-center mb-4"> <div> <h3 class="mb-1">Manage Categories</h3> <p class="text-muted mb-0">Create and manage exam categories</p> </div> <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addCategoryModal"> <i class="fas fa-plus me-2"></i>Add Category </button> </div> <div class="table-container"> <div class="table-responsive"> <table class="table table-hover" id="categoriesTable"> <thead class="table-light"> <tr> <th>ID</th> <th>Name</th> <th>Description</th> <th>Duration</th> <th>Passing %</th> <th>Questions</th> <th>Status</th> <th>Actions</th> </tr> </thead> <tbody> <?php try { $stmt = $pdo->query("SELECT * FROM categories ORDER BY created_at DESC"); $categories = $stmt->fetchAll(); if (!empty($categories)): foreach ($categories as $category): $statusBadge = $category['is_active'] ? 'success' : 'danger'; $statusText = $category['is_active'] ? 'Active' : 'Inactive'; $statusIcon = $category['is_active'] ? 'fa-toggle-on' : 'fa-toggle-off'; ?> <tr> <td><strong>#<?php echo $category['id']; ?></strong></td> <td> <div class="d-flex align-items-center"> <div class="category-icon bg-primary text-white rounded-circle me-2"> <i class="fas fa-folder"></i> </div> <div> <strong><?php echo htmlspecialchars($category['name']); ?></strong> </div> </div> </td> <td class="text-truncate" style="max-width: 200px;" title="<?php echo htmlspecialchars($category['description']); ?>"> <?php echo htmlspecialchars($category['description']); ?> </td> <td><?php echo $category['exam_duration']; ?> min</td> <td><?php echo $category['passing_marks']; ?>%</td> <td><span class="badge bg-info"><?php echo $category['total_questions']; ?></span></td> <td> <span class="badge bg-<?php echo $statusBadge; ?>"> <i class="fas <?php echo $statusIcon; ?> me-1"></i><?php echo $statusText; ?> </span> </td> <td class="action-buttons"> <button class="btn btn-sm btn-warning edit-category" data-id="<?php echo $category['id']; ?>" title="Edit"> <i class="fas fa-edit"></i> </button> <button class="btn btn-sm btn-info toggle-category" data-id="<?php echo $category['id']; ?>" data-status="<?php echo $category['is_active']; ?>" title="Toggle Status"> <i class="fas <?php echo $statusIcon; ?>"></i> </button> <button class="btn btn-sm btn-danger delete-category" data-id="<?php echo $category['id']; ?>" title="Delete"> <i class="fas fa-trash"></i> </button> </td> </tr> <?php endforeach; else: ?> <tr> <td colspan="8" class="text-center text-danger py-4"> <i class="fas fa-exclamation-triangle me-2"></i> No categories found </td> </tr> <?php endif; } catch(PDOException $e) { echo "<tr><td colspan='8' class='text-center text-danger py-4'> <i class='fas fa-exclamation-triangle me-2'></i> Error loading categories: " . htmlspecialchars($e->getMessage()) . " </td></tr>"; } ?> </tbody> </table> </div> </div> </div> <!-- Questions Management Tab --> <div id="questions-tab" class="tab-content"> <div class="d-flex justify-content-between align-items-center mb-4"> <div> <h3 class="mb-1">Manage Questions</h3> <p class="text-muted mb-0">Add, edit, and organize exam questions</p> </div> <div> <button class="btn btn-success me-2" data-bs-toggle="modal" data-bs-target="#importQuestionsModal"> <i class="fas fa-file-import me-2"></i>Import Excel </button> <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addQuestionModal"> <i class="fas fa-plus me-2"></i>Add Question </button> </div> </div> <div class="table-container"> <div class="table-responsive"> <table class="table table-hover" id="questionsTable"> <thead class="table-light"> <tr> <th>ID</th> <th>Category</th> <th>Question</th> <th>Options</th> <th>Correct Answer</th> <th>Marks</th> <th>Actions</th> </tr> </thead> <tbody> <?php try { $stmt = $pdo->query("SELECT q.*, c.name as category_name FROM questions q JOIN categories c ON q.category_id = c.id ORDER BY q.created_at DESC"); $questions = $stmt->fetchAll(); if (!empty($questions)): foreach ($questions as $question): $options = json_decode($question['options'], true); ?> <tr> <td><strong>#<?php echo $question['id']; ?></strong></td> <td> <span class="badge bg-primary"><?php echo htmlspecialchars($question['category_name']); ?></span> </td> <td class="text-truncate" style="max-width: 250px;" title="<?php echo htmlspecialchars($question['question_text']); ?>"> <?php echo htmlspecialchars($question['question_text']); ?> </td> <td> <button class="btn btn-sm btn-outline-info view-options" data-options='<?php echo htmlspecialchars(json_encode($options)); ?>' title="View Options"> <i class="fas fa-list"></i> View </button> </td> <td> <span class="badge bg-success">Option <?php echo strtoupper($question['correct_option']); ?></span> </td> <td><span class="badge bg-warning text-dark"><?php echo $question['marks']; ?></span></td> <td class="action-buttons"> <button class="btn btn-sm btn-warning edit-question" data-id="<?php echo $question['id']; ?>" title="Edit"> <i class="fas fa-edit"></i> </button> <button class="btn btn-sm btn-danger delete-question" data-id="<?php echo $question['id']; ?>" title="Delete"> <i class="fas fa-trash"></i> </button> </td> </tr> <?php endforeach; else: ?> <tr> <td colspan="7" class="text-center text-danger py-4"> <i class="fas fa-exclamation-triangle me-2"></i> No questions found </td> </tr> <?php endif; } catch(PDOException $e) { echo "<tr><td colspan='7' class='text-center text-danger py-4'> <i class='fas fa-exclamation-triangle me-2'></i> Error loading questions: " . htmlspecialchars($e->getMessage()) . " </td></tr>"; } ?> </tbody> </table> </div> </div> </div> <!-- Students Management Tab --> <div id="students-tab" class="tab-content"> <div class="d-flex justify-content-between align-items-center mb-4"> <div> <h3 class="mb-1">Manage Students</h3> <p class="text-muted mb-0">View and manage student accounts</p> </div> <div class="btn-group"> <button class="btn btn-outline-primary"> <i class="fas fa-download me-2"></i>Export </button> <button class="btn btn-outline-primary"> <i class="fas fa-filter me-2"></i>Filter </button> </div> </div> <div class="table-container"> <div class="table-responsive"> <table class="table table-hover"> <thead class="table-light"> <tr> <th>Student</th> <th>Email</th> <th>Phone</th> <th>Education</th> <th>Exams Taken</th> <th>Status</th> <th>Actions</th> </tr> </thead> <tbody> <?php try { $stmt = $pdo->query("SELECT s.*, (SELECT COUNT(*) FROM exams WHERE student_id = s.id) as exam_count FROM students s ORDER BY s.created_at DESC"); $students = $stmt->fetchAll(); if (!empty($students)): foreach ($students as $student): $statusClass = $student['is_active'] ? 'success' : 'secondary'; $statusText = $student['is_active'] ? 'Active' : 'Inactive'; ?> <tr> <td> <div class="d-flex align-items-center"> <div class="avatar bg-primary text-white rounded-circle me-2"> <?php echo strtoupper(substr($student['name'], 0, 1)); ?> </div> <div> <strong><?php echo htmlspecialchars($student['name']); ?></strong><br> <small class="text-muted">ID: <?php echo $student['id']; ?></small> </div> </div> </td> <td><?php echo htmlspecialchars($student['email']); ?></td> <td><?php echo htmlspecialchars($student['phone'] ?: 'N/A'); ?></td> <td><?php echo htmlspecialchars($student['education_level'] ?: 'N/A'); ?></td> <td> <span class="badge bg-info"><?php echo $student['exam_count']; ?></span> </td> <td> <span class="badge bg-<?php echo $statusClass; ?>"><?php echo $statusText; ?></span> </td> <td class="action-buttons"> <button class="btn btn-sm btn-info view-student" data-id="<?php echo $student['id']; ?>" title="View Profile"> <i class="fas fa-eye"></i> </button> <button class="btn btn-sm btn-warning toggle-student" data-id="<?php echo $student['id']; ?>" data-status="<?php echo $student['is_active']; ?>" title="Toggle Status"> <i class="fas fa-power-off"></i> </button> <button class="btn btn-sm btn-danger delete-student" data-id="<?php echo $student['id']; ?>" title="Delete"> <i class="fas fa-trash"></i> </button> </td> </tr> <?php endforeach; else: ?> <tr> <td colspan="7" class="text-center text-danger py-4"> <i class="fas fa-exclamation-triangle me-2"></i> No students found </td> </tr> <?php endif; } catch(PDOException $e) { echo "<tr><td colspan='7' class='text-center text-danger py-4'> <i class='fas fa-exclamation-triangle me-2'></i> Error loading students: " . htmlspecialchars($e->getMessage()) . " </td></tr>"; } ?> </tbody> </table> </div> </div> </div> <!-- Certificates Management Tab --> <div id="certificates-tab" class="tab-content"> <div class="d-flex justify-content-between align-items-center mb-4"> <div> <h3 class="mb-1">Manage Certificates</h3> <p class="text-muted mb-0">View and manage issued certificates</p> </div> </div> <div class="table-container"> <div class="table-responsive"> <table class="table table-hover"> <thead class="table-light"> <tr> <th>Certificate Code</th> <th>Student Name</th> <th>Category</th> <th>Score</th> <th>Issued Date</th> <th>Expiry Date</th> <th>Actions</th> </tr> </thead> <tbody> <?php try { $stmt = $pdo->query("SELECT cert.*, s.name as student_name, cat.name as category_name, e.score, e.total_marks FROM certificates cert JOIN students s ON cert.student_id = s.id JOIN exams e ON cert.exam_id = e.id JOIN categories cat ON e.category_id = cat.id ORDER BY cert.issued_date DESC"); $certificates = $stmt->fetchAll(); if (!empty($certificates)): foreach ($certificates as $certificate): ?> <tr> <td><code><?php echo htmlspecialchars($certificate['certificate_code']); ?></code></td> <td><?php echo htmlspecialchars($certificate['student_name']); ?></td> <td><?php echo htmlspecialchars($certificate['category_name']); ?></td> <td><?php echo $certificate['score']; ?>/<?php echo $certificate['total_marks']; ?></td> <td><?php echo date('M j, Y', strtotime($certificate['issued_date'])); ?></td> <td><?php echo date('M j, Y', strtotime($certificate['expiry_date'])); ?></td> <td class="action-buttons"> <button class="btn btn-sm btn-info view-certificate" data-id="<?php echo $certificate['id']; ?>" title="View Certificate"> <i class="fas fa-eye"></i> </button> <button class="btn btn-sm btn-success download-certificate" data-id="<?php echo $certificate['id']; ?>" title="Download Certificate"> <i class="fas fa-download"></i> </button> <button class="btn btn-sm btn-danger revoke-certificate" data-id="<?php echo $certificate['id']; ?>" title="Revoke Certificate"> <i class="fas fa-ban"></i> </button> </td> </tr> <?php endforeach; else: ?> <tr> <td colspan="7" class="text-center text-danger py-4"> <i class="fas fa-exclamation-triangle me-2"></i> No certificates found </td> </tr> <?php endif; } catch(PDOException $e) { echo "<tr><td colspan='7' class='text-center text-danger py-4'> <i class='fas fa-exclamation-triangle me-2'></i> Error loading certificates: " . htmlspecialchars($e->getMessage()) . " </td></tr>"; } ?> </tbody> </table> </div> </div> </div> <!-- Exam Results Tab --> <div id="exams-tab" class="tab-content"> <div class="d-flex justify-content-between align-items-center mb-4"> <div> <h3 class="mb-1">Exam Results</h3> <p class="text-muted mb-0">View and manage all exam results</p> </div> </div> <div class="table-container"> <div class="table-responsive"> <table class="table table-hover"> <thead class="table-light"> <tr> <th>Exam ID</th> <th>Student</th> <th>Category</th> <th>Score</th> <th>Percentage</th> <th>Status</th> <th>Time Taken</th> <th>Completed</th> <th>Actions</th> </tr> </thead> <tbody> <?php try { $stmt = $pdo->query("SELECT e.*, s.name as student_name, c.name as category_name, cert.id as cert_exists FROM exams e JOIN students s ON e.student_id = s.id JOIN categories c ON e.category_id = c.id LEFT JOIN certificates cert ON cert.exam_id = e.id ORDER BY e.completed_at DESC"); $exams = $stmt->fetchAll(); if (!empty($exams)): foreach ($exams as $exam): $statusBadge = $exam['status'] == 'passed' ? 'success' : ($exam['status'] == 'failed' ? 'danger' : 'warning'); $timeTaken = $exam['time_taken'] ? gmdate("H:i:s", $exam['time_taken']) : 'N/A'; $hasCertificate = !empty($exam['cert_exists']); ?> <tr> <td><?php echo $exam['id']; ?></td> <td><?php echo htmlspecialchars($exam['student_name']); ?></td> <td><?php echo htmlspecialchars($exam['category_name']); ?></td> <td><?php echo $exam['score'] . '/' . $exam['total_marks']; ?></td> <td><?php echo $exam['percentage']; ?>%</td> <td><span class="badge bg-<?php echo $statusBadge; ?>"><?php echo ucfirst($exam['status']); ?></span></td> <td><?php echo $timeTaken; ?></td> <td><?php echo date('M j, Y g:i A', strtotime($exam['completed_at'])); ?></td> <td class="action-buttons"> <button class="btn btn-sm btn-info view-exam-details" data-id="<?php echo $exam['id']; ?>" title="View Details"> <i class="fas fa-list"></i> </button> <?php if ($exam['status'] == 'passed' && !$hasCertificate): ?> <button class="btn btn-sm btn-success generate-certificate" data-id="<?php echo $exam['id']; ?>" title="Generate Certificate"> <i class="fas fa-certificate"></i> </button> <?php elseif ($hasCertificate): ?> <button class="btn btn-sm btn-warning view-certificate" data-id="<?php echo $exam['cert_exists']; ?>" title="View Certificate"> <i class="fas fa-eye"></i> </button> <?php endif; ?> </td> </tr> <?php endforeach; else: ?> <tr> <td colspan="9" class="text-center text-danger py-4"> <i class="fas fa-exclamation-triangle me-2"></i> No exam results found </td> </tr> <?php endif; } catch(PDOException $e) { echo "<tr><td colspan='9' class='text-center text-danger py-4'> <i class='fas fa-exclamation-triangle me-2'></i> Error loading exam results: " . htmlspecialchars($e->getMessage()) . " </td></tr>"; } ?> </tbody> </table> </div> </div> </div> <!-- Bulk Import Tab --> <div id="import-tab" class="tab-content"> <div class="d-flex justify-content-between align-items-center mb-4"> <div> <h3 class="mb-1">Bulk Import</h3> <p class="text-muted mb-0">Import questions from Excel/CSV files</p> </div> </div> <div class="import-section"> <div class="row align-items-center"> <div class="col-md-7"> <h4 class="mb-2"> <i class="fas fa-file-excel me-2"></i>Excel Import </h4> <p class="mb-0">Upload an Excel file to import multiple questions at once. Download the template file for correct formatting.</p> </div> <div class="col-md-5 text-end"> <button class="btn btn-light" id="downloadTemplate"> <i class="fas fa-download me-2"></i>Download Template </button> <button class="btn btn-light" data-bs-toggle="modal" data-bs-target="#importQuestionsModal"> <i class="fas fa-upload me-2"></i>Import Questions </button> </div> </div> </div> <div class="row mt-4"> <div class="col-md-6"> <div class="table-container"> <h5 class="mb-3"> <i class="fas fa-info-circle me-2"></i>Import Instructions </h5> <ul class="list-unstyled"> <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Use the provided template file</li> <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Ensure correct column order</li> <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Category names must match existing categories</li> <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Correct option should be A, B, C, or D</li> <li class="mb-2"><i class="fas fa-check text-success me-2"></i>File format: .xlsx or .csv</li> </ul> </div> </div> <div class="col-md-6"> <div class="table-container"> <h5 class="mb-3"> <i class="fas fa-history me-2"></i>Recent Imports </h5> <div class="list-group"> <div class="list-group-item d-flex justify-content-between align-items-center"> <div> <small class="text-muted">Today, 10:30 AM</small> <div>questions_import.xlsx</div> </div> <span class="badge bg-success">45 questions</span> </div> <div class="list-group-item d-flex justify-content-between align-items-center"> <div> <small class="text-muted">Yesterday, 3:15 PM</small> <div>data_science_questions.csv</div> </div> <span class="badge bg-success">32 questions</span> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> <!-- Import Questions Modal --> <div class="modal fade" id="importQuestionsModal" tabindex="-1" aria-labelledby="importQuestionsModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="importQuestionsModalLabel"> <i class="fas fa-file-import me-2"></i>Import Questions from Excel </h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <form id="importQuestionsForm" enctype="multipart/form-data" action="import_questions.php" method="POST"> <div class="modal-body"> <div class="file-upload-area" id="fileUploadArea"> <i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3"></i> <h5>Drag & Drop your Excel file here</h5> <p class="text-muted">or click to browse</p> <input type="file" id="excelFile" name="excel_file" accept=".xlsx,.xls,.csv" style="display: none;" required> <button type="button" class="btn btn-primary mt-2" onclick="document.getElementById('excelFile').click()"> <i class="fas fa-folder-open me-2"></i>Choose File </button> </div> <div id="fileName" class="text-center mt-3" style="display: none;"></div> <div class="row mt-4"> <div class="col-md-6"> <div class="mb-3"> <label for="categoryImport" class="form-label">Category</label> <select class="form-control" id="categoryImport" name="category_id" required> <option value="">Select Category</option> <?php $stmt = $pdo->query("SELECT id, name FROM categories WHERE is_active = 1"); while ($cat = $stmt->fetch()) { echo "<option value='{$cat['id']}'>{$cat['name']}</option>"; } ?> </select> </div> </div> <div class="col-md-6"> <div class="mb-3"> <label for="marksDefault" class="form-label">Default Marks</label> <input type="number" class="form-control" id="marksDefault" name="default_marks" value="1" min="1" required> </div> </div> </div> <div class="alert alert-info"> <h6><i class="fas fa-info-circle me-2"></i>File Format Requirements:</h6> <ul class="mb-0"> <li>File must be .xlsx, .xls, or .csv format</li> <li>Required columns: <code>question_text, option_a, option_b, option_c, option_d, correct_option</code></li> <li>Optional columns: <code>marks</code> (if not provided, default marks will be used)</li> <li><code>correct_option</code> should be: A, B, C, or D</li> </ul> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary" id="importSubmitBtn"> <i class="fas fa-upload me-2"></i>Import Questions </button> </div> </form> </div> </div> </div> <!-- Options Modal --> <div class="modal fade" id="optionsModal" tabindex="-1" aria-labelledby="optionsModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="optionsModalLabel">Question Options</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body" id="optionsModalBody"> <!-- Options will be loaded here --> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> </div> </div> </div> </div> <!-- Add other modals (Add Category, Add Question, etc.) here or include from external file --> <?php if (file_exists('admin_modals.php')) include 'admin_modals.php'; ?> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> <script> // Fixed Chart Initialization let performanceChart, categoryChart; function initializeCharts() { const performanceCtx = document.getElementById('performanceChart'); if (performanceChart) { performanceChart.destroy(); } performanceChart = new Chart(performanceCtx, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'], datasets: [{ label: 'Pass Rate', data: [65, 72, 68, 74, 78, 82, 85, 88], borderColor: '#4361ee', backgroundColor: 'rgba(67, 97, 238, 0.1)', tension: 0.4, fill: true, borderWidth: 3 }, { label: 'Average Score', data: [72, 75, 73, 76, 79, 81, 83, 85], borderColor: '#4cc9f0', backgroundColor: 'rgba(76, 201, 240, 0.1)', tension: 0.4, fill: true, borderWidth: 3 }] }, options: { maintainAspectRatio: false, responsive: true, scales: { y: { beginAtZero: true, max: 100, grid: { color: 'rgba(0,0,0,0.05)' } }, x: { grid: { display: false } } }, plugins: { legend: { position: 'top', } } } }); const categoryCtx = document.getElementById('categoryChart'); if (categoryChart) { categoryChart.destroy(); } categoryChart = new Chart(categoryCtx, { type: 'doughnut', data: { labels: ['Web Development', 'Data Science', 'Cybersecurity', 'Mobile Dev', 'Other'], datasets: [{ data: [35, 25, 20, 15, 5], backgroundColor: ['#4361ee', '#4cc9f0', '#3a0ca3', '#f6c23e', '#e74a3b'], hoverBackgroundColor: ['#3251d4', '#3bb9e0', '#2a0a8a', '#dda20a', '#d52a1a'], borderWidth: 2, borderColor: '#fff' }], }, options: { maintainAspectRatio: false, responsive: true, cutout: '65%', plugins: { legend: { position: 'bottom' } } }, }); } // Tab Management function showTab(tabName) { // Hide all tabs document.querySelectorAll('.tab-content').forEach(tab => { tab.classList.remove('active'); }); // Remove active class from all nav links document.querySelectorAll('.sidebar .nav-link').forEach(link => { link.classList.remove('active'); }); // Show selected tab and activate nav link document.getElementById(tabName + '-tab').classList.add('active'); event.target.classList.add('active'); // Update tab title const tabTitle = event.target.textContent.trim(); document.getElementById('currentTabTitle').textContent = tabTitle; // Reinitialize charts when dashboard is shown if (tabName === 'dashboard') { setTimeout(() => { initializeCharts(); }, 100); } } // Enhanced JavaScript functionality $(document).ready(function() { // Initialize charts initializeCharts(); // Initialize Select2 for dropdowns $('.select2').select2({ theme: 'bootstrap-5', width: '100%' }); // File upload functionality const fileUploadArea = document.getElementById('fileUploadArea'); const fileInput = document.getElementById('excelFile'); const fileName = document.getElementById('fileName'); if (fileUploadArea && fileInput) { fileUploadArea.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', function() { if (this.files.length > 0) { fileName.textContent = 'Selected file: ' + this.files[0].name; fileName.style.display = 'block'; fileUploadArea.style.borderColor = '#4361ee'; fileUploadArea.innerHTML = ` <i class="fas fa-file-excel fa-3x text-success mb-3"></i> <h5>File Selected</h5> <p class="text-muted">${this.files[0].name}</p> <button type="button" class="btn btn-outline-primary mt-2" onclick="document.getElementById('excelFile').click()"> <i class="fas fa-redo me-2"></i>Change File </button> `; } }); // Drag and drop functionality fileUploadArea.addEventListener('dragover', (e) => { e.preventDefault(); fileUploadArea.classList.add('dragover'); }); fileUploadArea.addEventListener('dragleave', () => { fileUploadArea.classList.remove('dragover'); }); fileUploadArea.addEventListener('drop', (e) => { e.preventDefault(); fileUploadArea.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { fileInput.files = files; fileName.textContent = 'Selected file: ' + files[0].name; fileName.style.display = 'block'; fileUploadArea.innerHTML = ` <i class="fas fa-file-excel fa-3x text-success mb-3"></i> <h5>File Selected</h5> <p class="text-muted">${files[0].name}</p> <button type="button" class="btn btn-outline-primary mt-2" onclick="document.getElementById('excelFile').click()"> <i class="fas fa-redo me-2"></i>Change File </button> `; } }); } // View options modal $(document).on('click', '.view-options', function() { try { const options = JSON.parse($(this).data('options')); let optionsHtml = ''; for (const [key, value] of Object.entries(options)) { optionsHtml += `<div class="mb-2"><strong>${key.toUpperCase()}:</strong> ${value}</div>`; } $('#optionsModalBody').html(optionsHtml); new bootstrap.Modal(document.getElementById('optionsModal')).show(); } catch (e) { alert('Error loading options: ' + e.message); } }); // Import form submission $('#importQuestionsForm').on('submit', function(e) { e.preventDefault(); const submitBtn = $('#importSubmitBtn'); const originalText = submitBtn.html(); submitBtn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin me-2"></i>Importing...'); const formData = new FormData(this); $.ajax({ url: 'import_questions.php', type: 'POST', data: formData, processData: false, contentType: false, success: function(response) { try { const result = JSON.parse(response); if (result.success) { alert('Success: ' + result.message); $('#importQuestionsModal').modal('hide'); // Refresh questions table showTab('questions'); location.reload(); // Reload to show new questions } else { alert('Error: ' + result.message); } } catch (e) { alert('Error parsing response: ' + response); } }, error: function(xhr, status, error) { alert('Upload failed: ' + error); }, complete: function() { submitBtn.prop('disabled', false).html(originalText); } }); }); // Download template $('#downloadTemplate').click(function() { // Create a simple CSV template for download const template = `question_text,option_a,option_b,option_c,option_d,correct_option,marks "What is the capital of France?","Paris","London","Berlin","Madrid","a",1 "What is 2+2?","3","4","5","6","b",1 "Which language is used for web development?","Java","Python","JavaScript","C++","c",1`; const blob = new Blob([template], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'question_import_template.csv'; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); }); // Generate certificate $(document).on('click', '.generate-certificate', function() { const examId = $(this).data('id'); if(confirm('Generate certificate for this exam?')) { window.open('generate_certificate.php?exam_id=' + examId, '_blank'); } }); // Enhanced delete confirmations $(document).on('click', '.delete-category, .delete-question, .delete-student, .revoke-certificate', function() { if(!confirm('Are you sure you want to delete this item? This action cannot be undone.')) { return false; } // Implement AJAX delete functionality here const itemId = $(this).data('id'); const itemType = $(this).hasClass('delete-category') ? 'category' : $(this).hasClass('delete-question') ? 'question' : $(this).hasClass('delete-student') ? 'student' : 'certificate'; // You would typically make an AJAX call here to delete the item // For now, we'll just reload the page location.reload(); }); // Toggle actions $(document).on('click', '.toggle-category, .toggle-student', function() { const itemId = $(this).data('id'); const currentStatus = $(this).data('status'); const newStatus = currentStatus == 1 ? 0 : 1; const itemType = $(this).hasClass('toggle-category') ? 'category' : 'student'; if(confirm('Are you sure you want to ' + (newStatus ? 'activate' : 'deactivate') + ' this ' + itemType + '?')) { // You would typically make an AJAX call here to toggle the status // For now, we'll just reload the page location.reload(); } }); }); // Make showTab function globally available window.showTab = showTab; </script> </body> </html>
Coded With 💗 by
HanzOFC