This commit is contained in:
Flatlogic Bot 2025-10-14 15:07:23 +00:00
parent e40e03403c
commit fd7bfb0869
8 changed files with 379 additions and 10 deletions

125
certificate.php Normal file
View File

@ -0,0 +1,125 @@
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
require_once 'db/config.php';
$db = db();
$skill_id = $_GET['skill_id'] ?? 0;
$user_id = $_SESSION['user_id'];
// Fetch user name
$user_stmt = $db->prepare("SELECT name FROM users WHERE id = ?");
$user_stmt->execute([$user_id]);
$user_name = $user_stmt->fetchColumn();
// Fetch skill title
$skill_stmt = $db->prepare("SELECT title FROM skills WHERE id = ?");
$skill_stmt->execute([$skill_id]);
$skill_title = $skill_stmt->fetchColumn();
// Fetch latest quiz attempt with a score of 70% or higher
$attempt_stmt = $db->prepare("SELECT score, completed_at FROM quiz_attempts WHERE user_id = ? AND skill_id = ? AND score >= 70 ORDER BY completed_at DESC LIMIT 1");
$attempt_stmt->execute([$user_id, $skill_id]);
$attempt = $attempt_stmt->fetch(PDO::FETCH_ASSOC);
if (!$user_name || !$skill_title || !$attempt) {
// Redirect or show an error if the user is not eligible for a certificate
header('Location: dashboard.php?error=not_eligible');
exit;
}
$completion_date = date("F j, Y", strtotime($attempt['completed_at']));
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Certificate of Completion</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<style>
body {
background-color: #f0f2f5;
}
.certificate-container {
max-width: 800px;
margin: 50px auto;
padding: 40px;
background: white;
border: 10px solid #0d6efd;
border-radius: 15px;
box-shadow: 0 0 20px rgba(0,0,0,0.1);
text-align: center;
font-family: serif;
position: relative;
}
.certificate-container::before, .certificate-container::after {
content: '';
position: absolute;
left: -15px;
top: -15px;
right: -15px;
bottom: -15px;
border: 2px solid #0d6efd;
border-radius: 15px;
}
.certificate-title {
font-size: 48px;
font-weight: bold;
color: #0d6efd;
margin-bottom: 20px;
}
.certificate-subtitle {
font-size: 24px;
color: #6c757d;
margin-bottom: 30px;
}
.user-name {
font-size: 40px;
font-weight: bold;
color: #343a40;
margin-bottom: 20px;
border-bottom: 2px solid #dee2e6;
display: inline-block;
padding-bottom: 10px;
}
.completion-text {
font-size: 20px;
margin-bottom: 30px;
}
.skill-title {
font-size: 28px;
font-style: italic;
color: #495057;
}
.completion-date {
font-size: 18px;
color: #6c757d;
margin-top: 40px;
}
.actions {
margin-top: 30px;
}
</style>
</head>
<body>
<div class="certificate-container">
<div class="certificate-title">Certificate of Completion</div>
<div class="certificate-subtitle">This is to certify that</div>
<div class="user-name"><?php echo htmlspecialchars($user_name); ?></div>
<div class="completion-text">has successfully completed the skill</div>
<div class="skill-title">"<?php echo htmlspecialchars($skill_title); ?>"</div>
<div class="completion-date">on <?php echo $completion_date; ?></div>
<div class="actions">
<a href="dashboard.php" class="btn btn-secondary"><i class="bi bi-arrow-left"></i> Back to Dashboard</a>
<button onclick="window.print()" class="btn btn-primary"><i class="bi bi-printer"></i> Print Certificate</button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS lesson_completion (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT(11) UNSIGNED NOT NULL,
lesson_id INT(11) NOT NULL,
completed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE,
UNIQUE KEY (user_id, lesson_id)
);

View File

@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS quizzes (
id INT AUTO_INCREMENT PRIMARY KEY,
skill_id INT NOT NULL,
question TEXT NOT NULL,
option_a VARCHAR(255) NOT NULL,
option_b VARCHAR(255) NOT NULL,
option_c VARCHAR(255) NOT NULL,
option_d VARCHAR(255) NOT NULL,
correct_option CHAR(1) NOT NULL,
FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE
);

View File

@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS quiz_attempts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT(11) UNSIGNED NOT NULL,
skill_id INT NOT NULL,
score INT NOT NULL,
completed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE
);

View File

@ -0,0 +1,6 @@
INSERT INTO quizzes (skill_id, question, option_a, option_b, option_c, option_d, correct_option) VALUES
(1, 'What does HTML stand for?', 'Hyper Text Markup Language', 'High Tech Modern Language', 'Hyperlink and Text Markup Language', 'Home Tool Markup Language', 'a'),
(1, 'Who is making the Web standards?', 'Mozilla', 'The World Wide Web Consortium', 'Google', 'Microsoft', 'b'),
(1, 'Choose the correct HTML element for the largest heading:', '<h1>', '<heading>', '<h6>', '<head>', 'a'),
(1, 'What is the correct HTML element for inserting a line break?', '<lb>', '<br>', '<break>', '<linebreak>', 'b'),
(1, 'What is the correct HTML for creating a hyperlink?', '<a href="http://www.example.com">Example</a>', '<a>http://www.example.com</a>', '<a url="http://www.example.com">Example</a>', '<link>http://www.example.com</link>', 'a');

View File

@ -9,12 +9,11 @@ try {
echo "Users table definition:\n";
print_r($user_table_def);
$stmt = $pdo->query("SHOW CREATE TABLE skills");
$skill_table_def = $stmt->fetch(PDO::FETCH_ASSOC);
echo "\nSkills table definition:\n";
print_r($skill_table_def);
$stmt = $pdo->query("SHOW CREATE TABLE lessons");
$lesson_table_def = $stmt->fetch(PDO::FETCH_ASSOC);
echo "\nLessons table definition:\n";
print_r($lesson_table_def);
} catch (PDOException $e) {
die("Database query failed: " . $e->getMessage());
}

108
learn.php
View File

@ -8,6 +8,41 @@ require_once 'db/config.php';
$db = db();
$skill_id = $_GET['skill_id'] ?? 0;
$user_id = $_SESSION['user_id'];
// Handle marking a lesson as complete
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['complete_lesson'])) {
$lesson_id = $_POST['lesson_id'];
// Check if already completed
$stmt = $db->prepare("SELECT id FROM lesson_completion WHERE user_id = ? AND lesson_id = ?");
$stmt->execute([$user_id, $lesson_id]);
if ($stmt->fetch()) {
// Already completed, do nothing
} else {
// Insert into lesson_completion
$stmt = $db->prepare("INSERT INTO lesson_completion (user_id, lesson_id) VALUES (?, ?)");
$stmt->execute([$user_id, $lesson_id]);
// Recalculate progress
$total_lessons_stmt = $db->prepare("SELECT COUNT(*) FROM lessons l JOIN modules m ON l.module_id = m.id WHERE m.skill_id = ?");
$total_lessons_stmt->execute([$skill_id]);
$total_lessons = $total_lessons_stmt->fetchColumn();
$completed_lessons_stmt = $db->prepare("SELECT COUNT(*) FROM lesson_completion lc JOIN lessons l ON lc.lesson_id = l.id JOIN modules m ON l.module_id = m.id WHERE lc.user_id = ? AND m.skill_id = ?");
$completed_lessons_stmt->execute([$user_id, $skill_id]);
$completed_lessons = $completed_lessons_stmt->fetchColumn();
$progress = ($total_lessons > 0) ? round(($completed_lessons / $total_lessons) * 100) : 0;
// Update enrollments table
$update_stmt = $db->prepare("UPDATE enrollments SET progress = ? WHERE user_id = ? AND skill_id = ?");
$update_stmt->execute([$progress, $user_id, $skill_id]);
}
header("Location: learn.php?skill_id=$skill_id");
exit;
}
// Fetch skill details
$stmt = $db->prepare("SELECT * FROM skills WHERE id = ?");
@ -18,6 +53,11 @@ if (!$skill) {
die('Skill not found!');
}
// Fetch completed lesson IDs for the user
$completed_lessons_stmt = $db->prepare("SELECT lesson_id FROM lesson_completion WHERE user_id = ?");
$completed_lessons_stmt->execute([$user_id]);
$completed_lesson_ids = $completed_lessons_stmt->fetchAll(PDO::FETCH_COLUMN);
// Fetch modules and lessons
$modules_stmt = $db->prepare("SELECT * FROM modules WHERE skill_id = ? ORDER BY `order` ASC");
$modules_stmt->execute([$skill_id]);
@ -25,6 +65,13 @@ $modules = $modules_stmt->fetchAll(PDO::FETCH_ASSOC);
$lessons_stmt = $db->prepare("SELECT * FROM lessons WHERE module_id = ? ORDER BY `order` ASC");
// Calculate progress
$total_lessons_stmt = $db->prepare("SELECT COUNT(*) FROM lessons l JOIN modules m ON l.module_id = m.id WHERE m.skill_id = ?");
$total_lessons_stmt->execute([$skill_id]);
$total_lessons = $total_lessons_stmt->fetchColumn();
$completed_lessons = count($completed_lesson_ids);
$progress = ($total_lessons > 0) ? round(($completed_lessons / $total_lessons) * 100) : 0;
?>
<!DOCTYPE html>
<html lang="en">
@ -33,6 +80,7 @@ $lessons_stmt = $db->prepare("SELECT * FROM lessons WHERE module_id = ? ORDER BY
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Learning: <?php echo htmlspecialchars($skill['title']); ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
@ -40,6 +88,12 @@ $lessons_stmt = $db->prepare("SELECT * FROM lessons WHERE module_id = ? ORDER BY
<a href="dashboard.php" class="btn btn-secondary mb-4">Back to Dashboard</a>
<h1><?php echo htmlspecialchars($skill['title']); ?></h1>
<p class="text-muted"><?php echo htmlspecialchars($skill['category']); ?></p>
<!-- Progress Bar -->
<div class="progress my-4" style="height: 25px;">
<div class="progress-bar bg-success" role="progressbar" style="width: <?php echo $progress; ?>%;" aria-valuenow="<?php echo $progress; ?>" aria-valuemin="0" aria-valuemax="100"><?php echo $progress; ?>% Complete</div>
</div>
<hr>
<p><?php echo nl2br(htmlspecialchars($skill['description'])); ?></p>
@ -66,10 +120,25 @@ $lessons_stmt = $db->prepare("SELECT * FROM lessons WHERE module_id = ? ORDER BY
<p>No lessons in this module yet.</p>
<?php else: ?>
<ul class="list-group">
<?php foreach ($lessons as $lesson): ?>
<li class="list-group-item">
<h5><?php echo htmlspecialchars($lesson['title']); ?></h5>
<?php foreach ($lessons as $lesson):
$is_completed = in_array($lesson['id'], $completed_lesson_ids);
?>
<li class="list-group-item d-flex justify-content-between align-items-center <?php echo $is_completed ? 'list-group-item-light text-muted' : ''; ?>">
<div>
<h5>
<?php if ($is_completed): ?>
<i class="bi bi-check-circle-fill text-success"></i>
<?php endif; ?>
<?php echo htmlspecialchars($lesson['title']); ?>
</h5>
<p><?php echo nl2br(htmlspecialchars($lesson['content'])); ?></p>
</div>
<?php if (!$is_completed): ?>
<form method="POST" action="learn.php?skill_id=<?php echo $skill_id; ?>">
<input type="hidden" name="lesson_id" value="<?php echo $lesson['id']; ?>">
<button type="submit" name="complete_lesson" class="btn btn-sm btn-success">Mark as Complete</button>
</form>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
@ -81,6 +150,39 @@ $lessons_stmt = $db->prepare("SELECT * FROM lessons WHERE module_id = ? ORDER BY
<?php endif; ?>
</div>
</div>
<?php
// Fetch last quiz attempt
$quiz_attempt_stmt = $db->prepare("SELECT * FROM quiz_attempts WHERE user_id = ? AND skill_id = ? ORDER BY completed_at DESC LIMIT 1");
$quiz_attempt_stmt->execute([$user_id, $skill_id]);
$quiz_attempt = $quiz_attempt_stmt->fetch(PDO::FETCH_ASSOC);
?>
<?php if ($progress >= 100): ?>
<div class="card my-4">
<div class="card-body text-center">
<?php if ($quiz_attempt): ?>
<h4 class="card-title">Quiz Result</h4>
<p class="card-text">You scored <strong><?php echo $quiz_attempt['score']; ?>%</strong> on your last attempt.</p>
<?php if ($quiz_attempt['score'] >= 70): ?>
<a href="certificate.php?skill_id=<?php echo $skill_id; ?>" class="btn btn-success">
<i class="bi bi-patch-check-fill"></i> View Certificate
</a>
<?php else: ?>
<p class="text-danger">You need a score of 70% or higher to get a certificate.</p>
<a href="quiz.php?skill_id=<?php echo $skill_id; ?>" class="btn btn-primary">
<i class="bi bi-arrow-clockwise"></i> Retake Quiz
</a>
<?php endif; ?>
<?php else: ?>
<h4 class="card-title">Ready to test your knowledge?</h4>
<p class="card-text">You have completed all the lessons. It's time to take the quiz!</p>
<a href="quiz.php?skill_id=<?php echo $skill_id; ?>" class="btn btn-primary btn-lg">Take Quiz</a>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>

108
quiz.php Normal file
View File

@ -0,0 +1,108 @@
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
require_once 'db/config.php';
$db = db();
$skill_id = $_GET['skill_id'] ?? 0;
$user_id = $_SESSION['user_id'];
// Fetch skill details
$stmt = $db->prepare("SELECT title FROM skills WHERE id = ?");
$stmt->execute([$skill_id]);
$skill_title = $stmt->fetchColumn();
if (!$skill_title) {
die('Skill not found!');
}
// Fetch quiz questions
$questions_stmt = $db->prepare("SELECT * FROM quizzes WHERE skill_id = ?");
$questions_stmt->execute([$skill_id]);
$questions = $questions_stmt->fetchAll(PDO::FETCH_ASSOC);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$score = 0;
$total_questions = count($questions);
foreach ($questions as $question) {
$question_id = $question['id'];
$user_answer = $_POST['question_' . $question_id] ?? '';
if ($user_answer === $question['correct_option']) {
$score++;
}
}
$percentage_score = ($total_questions > 0) ? round(($score / $total_questions) * 100) : 0;
// Save quiz attempt
$insert_stmt = $db->prepare("INSERT INTO quiz_attempts (user_id, skill_id, score) VALUES (?, ?, ?)");
$insert_stmt->execute([$user_id, $skill_id, $percentage_score]);
header("Location: learn.php?skill_id=$skill_id");
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Quiz: <?php echo htmlspecialchars($skill_title); ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<div class="container mt-5">
<a href="learn.php?skill_id=<?php echo $skill_id; ?>" class="btn btn-secondary mb-4">Back to Learning</a>
<h1>Quiz: <?php echo htmlspecialchars($skill_title); ?></h1>
<?php if (empty($questions)): ?>
<div class="alert alert-warning">No quiz questions available for this skill yet.</div>
<?php else: ?>
<form method="POST">
<?php foreach ($questions as $index => $question): ?>
<div class="card my-4">
<div class="card-header">
<h5 class="mb-0">Question <?php echo $index + 1; ?></h5>
</div>
<div class="card-body">
<p class="card-text"><?php echo htmlspecialchars($question['question']); ?></p>
<div class="form-check">
<input class="form-check-input" type="radio" name="question_<?php echo $question['id']; ?>" id="q<?php echo $question['id']; ?>_a" value="a" required>
<label class="form-check-label" for="q<?php echo $question['id']; ?>_a">
<?php echo htmlspecialchars($question['option_a']); ?>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="question_<?php echo $question['id']; ?>" id="q<?php echo $question['id']; ?>_b" value="b">
<label class="form-check-label" for="q<?php echo $question['id']; ?>_b">
<?php echo htmlspecialchars($question['option_b']); ?>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="question_<?php echo $question['id']; ?>" id="q<?php echo $question['id']; ?>_c" value="c">
<label class="form-check-label" for="q<?php echo $question['id']; ?>_c">
<?php echo htmlspecialchars($question['option_c']); ?>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="question_<?php echo $question['id']; ?>" id="q<?php echo $question['id']; ?>_d" value="d">
<label class="form-check-label" for="q<?php echo $question['id']; ?>_d">
<?php echo htmlspecialchars($question['option_d']); ?>
</label>
</div>
</div>
</div>
<?php endforeach; ?>
<button type="submit" class="btn btn-primary btn-lg">Submit Quiz</button>
</form>
<?php endif; ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>