Compare commits

..

No commits in common. "ai-dev" and "master" have entirely different histories.

26 changed files with 145 additions and 1772 deletions

View File

@ -1,151 +0,0 @@
body {
font-family: 'Lato', sans-serif;
color: #264653;
background-color: #F4F4F4;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Poppins', sans-serif;
font-weight: 700;
}
.navbar {
background-color: #FFFFFF;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.navbar-brand {
font-family: 'Poppins', sans-serif;
font-weight: 700;
color: #2A9D8F !important;
}
.nav-link {
color: #264653 !important;
}
.nav-link:hover {
color: #2A9D8F !important;
}
.hero {
background: linear-gradient(45deg, #2A9D8F, #2de0c9);
color: white;
padding: 100px 0;
text-align: center;
}
.hero h1 {
font-size: 3.5rem;
font-weight: 700;
}
.hero p {
font-size: 1.25rem;
margin-bottom: 30px;
}
.btn-primary {
background-color: #E9C46A;
border-color: #E9C46A;
color: #264653;
padding: 12px 30px;
font-size: 1.1rem;
font-weight: 700;
border-radius: 0.5rem;
transition: background-color 0.3s;
}
.btn-primary:hover {
background-color: #f0d28a;
border-color: #f0d28a;
}
section {
padding: 80px 0;
}
section h2 {
text-align: center;
margin-bottom: 60px;
font-size: 2.5rem;
color: #264653;
}
.feature-card {
background-color: #FFFFFF;
border: none;
border-radius: 0.5rem;
padding: 30px;
text-align: center;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
transition: transform 0.3s;
}
.feature-card:hover {
transform: translateY(-10px);
}
.feature-icon {
font-size: 3rem;
color: #2A9D8F;
margin-bottom: 20px;
}
.testimonial-card {
background-color: #FFFFFF;
border-radius: 0.5rem;
padding: 30px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
#contact {
background-color: #FFFFFF;
}
.form-control {
border-radius: 0.5rem;
padding: 15px;
}
.form-control:focus {
border-color: #2A9D8F;
box-shadow: 0 0 0 0.25rem rgba(42, 157, 143, 0.25);
}
footer {
background-color: #264653;
color: white;
padding: 40px 0;
text-align: center;
}
footer a {
color: #E9C46A;
}
/* Dashboard Styles */
.sidebar {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 280px;
padding: 20px;
background-color: #fff;
border-right: 1px solid #dee2e6;
}
.sidebar .nav-link {
color: #333;
font-weight: 500;
}
.sidebar .nav-link.active {
color: #0d6efd;
}
.sidebar .nav-link .bi {
margin-right: 10px;
}
.main-content {
margin-left: 280px;
padding: 20px;
}

View File

@ -1,125 +0,0 @@
<?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

@ -1,49 +0,0 @@
<?php
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/mail/MailService.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');
if (empty($name) || empty($email) || empty($message) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Invalid input.']);
exit;
}
try {
$pdo = db();
$stmt = $pdo->prepare("INSERT INTO contact_submissions (name, email, message) VALUES (?, ?, ?)");
$stmt->execute([$name, $email, $message]);
} catch (PDOException $e) {
// In a real app, you would log this error.
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Database error.']);
exit;
}
$to = 'usmanabdulhamidsaleh4@gmail.com';
$subject = 'New Contact Form Submission';
$emailBody = "<p>You have a new contact form submission:</p>"
. "<ul>"
. "<li><strong>Name:</strong> " . htmlspecialchars($name) . "</li>"
. "<li><strong>Email:</strong> " . htmlspecialchars($email) . "</li>"
. "<li><strong>Message:</strong><br>" . nl2br(htmlspecialchars($message)) . "</li>"
. "</ul>";
$result = MailService::sendMail($to, $subject, $emailBody, strip_tags($emailBody), ['reply_to' => $email]);
if ($result['success']) {
echo json_encode(['success' => true, 'message' => 'Message sent successfully!']);
} else {
// In a real app, you would log this error.
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Failed to send email.']);
}
} else {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Method not allowed.']);
}

View File

@ -1,233 +0,0 @@
<?php
session_start();
require_once 'db/config.php';
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit;
}
$userId = $_SESSION['user_id'];
$message = '';
$message_type = '';
// Handle Enrollment
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['enroll_skill_id'])) {
$skillId = $_POST['enroll_skill_id'];
// Check if already enrolled
$stmt = db()->prepare("SELECT id FROM enrollments WHERE user_id = ? AND skill_id = ?");
$stmt->execute([$userId, $skillId]);
if ($stmt->fetch()) {
$_SESSION['message'] = "You are already enrolled in this skill.";
$_SESSION['message_type'] = 'warning';
} else {
// Enroll user
$stmt = db()->prepare("INSERT INTO enrollments (user_id, skill_id, progress, date_enrolled) VALUES (?, ?, 0, NOW())");
if ($stmt->execute([$userId, $skillId])) {
$_SESSION['message'] = "Enrollment successful! You can now continue learning from your dashboard.";
$_SESSION['message_type'] = 'success';
} else {
$_SESSION['message'] = "An error occurred. Please try again.";
$_SESSION['message_type'] = 'danger';
}
}
header("Location: dashboard.php");
exit;
}
if (isset($_SESSION['message'])) {
$message = $_SESSION['message'];
$message_type = $_SESSION['message_type'];
unset($_SESSION['message']);
unset($_SESSION['message_type']);
}
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$userId]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
session_destroy();
header("Location: login.php");
exit;
}
// Fetch all skills, excluding those the user is already enrolled in for the explorer
$enrolled_skill_ids = [];
$stmt_enrolled_ids = db()->prepare("SELECT skill_id FROM enrollments WHERE user_id = ?");
$stmt_enrolled_ids->execute([$userId]);
$enrolled_skill_ids = $stmt_enrolled_ids->fetchAll(PDO::FETCH_COLUMN);
$skills_by_category = [];
$sql = "SELECT * FROM skills";
if (!empty($enrolled_skill_ids)) {
$placeholders = implode(',', array_fill(0, count($enrolled_skill_ids), '?'));
$sql .= " WHERE id NOT IN ($placeholders)";
}
$sql .= " ORDER BY category, title";
$stmt = db()->prepare($sql);
if (!empty($enrolled_skill_ids)) {
$stmt->execute($enrolled_skill_ids);
} else {
$stmt->execute();
}
$all_skills = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($all_skills as $skill) {
$skills_by_category[$skill['category']][] = $skill;
}
// Fetch enrolled skills for the current user
$stmt = db()->prepare("
SELECT s.id, s.title, s.category, s.thumbnail, e.progress
FROM enrollments e
JOIN skills s ON e.skill_id = s.id
WHERE e.user_id = ?
");
$stmt->execute([$userId]);
$enrolled_skills = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard - TAP2SKILL</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<div class="sidebar">
<a class="navbar-brand" href="index.php">TAP2SKILL</a>
<hr>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="dashboard.php">
<i class="bi bi-grid-1x2-fill"></i>
Dashboard
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="bi bi-person-circle"></i>
Profile
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="bi bi-gear-fill"></i>
Settings
</a>
</li>
</ul>
<hr>
<a href="logout.php" class="btn btn-outline-primary">Logout</a>
</div>
<div class="main-content">
<div class="container-fluid">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Welcome, <?php echo htmlspecialchars($user['username']); ?>!</h1>
</div>
<?php if ($message): ?>
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
<?php echo htmlspecialchars($message); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<!-- Quick Access Buttons -->
<div class="row mb-4">
<div class="col-md-4">
<a href="#skill-explorer" class="btn btn-primary btn-lg w-100">Explore Skills</a>
</div>
<div class="col-md-4">
<a href="#enrolled-skills" class="btn btn-success btn-lg w-100">Continue Learning</a>
</div>
<div class="col-md-4">
<a href="#" class="btn btn-info btn-lg w-100">Community</a>
</div>
</div>
<!-- Enrolled Skills Section -->
<section id="enrolled-skills" class="mb-5">
<h2 class="h4">My Enrolled Skills</h2>
<div class="row">
<?php if (empty($enrolled_skills)): ?>
<div class="col">
<div class="card">
<div class="card-body text-center">
<p class="card-text">You havent enrolled in any skills yet. Explore new skills to start learning!</p>
<a href="#skill-explorer" class="btn btn-primary">Explore Skills</a>
</div>
</div>
</div>
<?php else: ?>
<?php foreach ($enrolled_skills as $skill): ?>
<div class="col-md-6 col-lg-4 mb-3">
<div class="card">
<img src="<?php echo htmlspecialchars($skill['thumbnail']); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($skill['title']); ?>">
<div class="card-body">
<h5 class="card-title"><?php echo htmlspecialchars($skill['title']); ?></h5>
<p class="card-text text-muted"><?php echo htmlspecialchars($skill['category']); ?></p>
<div class="progress mb-2">
<div class="progress-bar" role="progressbar" style="width: <?php echo $skill['progress']; ?>%;" aria-valuenow="<?php echo $skill['progress']; ?>" aria-valuemin="0" aria-valuemax="100"><?php echo $skill['progress']; ?>%</div>
</div>
<a href="learn.php?skill_id=<?php echo $skill['id']; ?>" class="btn btn-primary mt-3">Continue Learning</a>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</section>
<!-- Skill Explorer Section -->
<section id="skill-explorer">
<h2 class="h4">Skill Explorer</h2>
<?php if (empty($all_skills)): ?>
<div class="col">
<div class="card">
<div class="card-body text-center">
<p class="card-text">You've enrolled in all available skills. Great job!</p>
</div>
</div>
</div>
<?php else: ?>
<?php foreach ($skills_by_category as $category => $skills): ?>
<h3 class="h5 mt-4"><?php echo htmlspecialchars($category); ?></h3>
<div class="row">
<?php foreach ($skills as $skill): ?>
<div class="col-md-6 col-lg-3 mb-3">
<div class="card h-100">
<img src="<?php echo htmlspecialchars($skill['thumbnail']); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($skill['title']); ?>">
<div class="card-body d-flex flex-column">
<h5 class="card-title"><?php echo htmlspecialchars($skill['title']); ?></h5>
<p class="card-text flex-grow-1"><?php echo htmlspecialchars($skill['description']); ?></p>
<form method="POST" action="dashboard.php" class="mt-auto">
<input type="hidden" name="enroll_skill_id" value="<?php echo $skill['id']; ?>">
<button type="submit" class="btn btn-outline-primary">Enroll</button>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</section>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -1,21 +0,0 @@
<?php
require_once __DIR__ . '/config.php';
try {
$pdo = db();
$migration_files = glob(__DIR__ . '/migrations/*.sql');
sort($migration_files);
foreach ($migration_files as $file) {
echo "Running migration: " . basename($file) . "...\n";
$sql = file_get_contents($file);
$pdo->exec($sql);
echo "Success.\n";
}
echo "\nAll migrations completed successfully!\n";
} catch (PDOException $e) {
die("Database migration failed: " . $e->getMessage());
}

View File

@ -1,8 +0,0 @@
CREATE TABLE IF NOT EXISTS contact_submissions (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

View File

@ -1,7 +0,0 @@
CREATE TABLE IF NOT EXISTS `users` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(255) NOT NULL UNIQUE,
`email` VARCHAR(255) NOT NULL UNIQUE,
`password` VARCHAR(255) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -1,7 +0,0 @@
CREATE TABLE IF NOT EXISTS `skills` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(255) NOT NULL,
`category` VARCHAR(100) NOT NULL,
`description` TEXT,
`thumbnail` VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -1,8 +0,0 @@
CREATE TABLE IF NOT EXISTS `user_skills` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`user_id` int(11) unsigned NOT NULL,
`skill_id` int(11) NOT NULL,
`progress` INT DEFAULT 0,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (skill_id) REFERENCES skills(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -1,11 +0,0 @@
INSERT INTO `skills` (`title`, `category`, `description`, `thumbnail`) VALUES
('Introduction to Python', 'Tech', 'Learn the fundamentals of Python programming.', 'assets/images/python.png'),
('Web Development Basics', 'Tech', 'Understand HTML, CSS, and JavaScript.', 'assets/images/webdev.png'),
('Data Analysis with Pandas', 'Tech', 'Analyze data effectively using the Pandas library.', 'assets/images/pandas.png'),
('Basic Carpentry', 'Trade', 'Learn to build simple wooden furniture.', 'assets/images/carpentry.png'),
('Electrical Wiring 101', 'Trade', 'Understand the basics of home electrical wiring.', 'assets/images/wiring.png'),
('Digital Painting', 'Art', 'Create stunning digital art with this introductory course.', 'assets/images/digital_painting.png'),
('Music Production Fundamentals', 'Art', 'Learn to produce your own music from scratch.', 'assets/images/music_production.png'),
('Introduction to Business', 'Business', 'Learn the basics of starting and running a business.', 'assets/images/business.png'),
('Marketing for Beginners', 'Business', 'Understand the fundamentals of modern marketing.', 'assets/images/marketing.png'),
('Personal Finance Management', 'Business', 'Take control of your finances.', 'assets/images/finance.png');

View File

@ -1,16 +0,0 @@
-- This migration cleans up previous attempts and creates the enrollments table correctly.
DROP TABLE IF EXISTS `user_skills`;
DROP TABLE IF EXISTS `enrollments`;
CREATE TABLE `enrollments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL,
`skill_id` int(11) NOT NULL,
`progress` int(11) NOT NULL DEFAULT 0,
`date_enrolled` DATETIME NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `skill_id` (`skill_id`),
CONSTRAINT `enrollments_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `enrollments_ibfk_2` FOREIGN KEY (`skill_id`) REFERENCES `skills` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

View File

@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS modules (
id INT AUTO_INCREMENT PRIMARY KEY,
skill_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
`order` INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE
);

View File

@ -1,10 +0,0 @@
CREATE TABLE IF NOT EXISTS lessons (
id INT AUTO_INCREMENT PRIMARY KEY,
module_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT,
`order` INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (module_id) REFERENCES modules(id) ON DELETE CASCADE
);

View File

@ -1,3 +0,0 @@
INSERT INTO modules (skill_id, title, `order`) VALUES
(1, 'Module 1: Getting Started', 1),
(1, 'Module 2: Core Concepts', 2);

View File

@ -1,5 +0,0 @@
INSERT INTO lessons (module_id, title, content, `order`) VALUES
(1, 'Lesson 1.1: Introduction to the topic', 'This is the content for the introductory lesson.', 1),
(1, 'Lesson 1.2: Setting up your environment', 'Here is how you set up your environment to get started.', 2),
(2, 'Lesson 2.1: Understanding the fundamentals', 'This lesson covers the fundamental principles.', 1),
(2, 'Lesson 2.2: Advanced techniques', 'This lesson delves into more advanced techniques.', 2);

View File

@ -1,9 +0,0 @@
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

@ -1,11 +0,0 @@
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

@ -1,9 +0,0 @@
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

@ -1,6 +0,0 @@
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

@ -1,19 +0,0 @@
<?php
require_once __DIR__ . '/config.php';
try {
$pdo = db();
$stmt = $pdo->query("SHOW CREATE TABLE users");
$user_table_def = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Users table definition:\n";
print_r($user_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());
}

439
index.php
View File

@ -1,299 +1,150 @@
<!DOCTYPE html>
<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TAP2SKILL - Learn. Hustle. Thrive.</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Lato:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #2A9D8F;
--secondary-color: #E9C46A;
--background-color: #F4F4F4;
--surface-color: #FFFFFF;
--text-color: #264653;
--gradient-start: #2A9D8F;
--gradient-end: #3aafa9;
}
body {
font-family: 'Lato', sans-serif;
margin: 0;
background-color: var(--background-color);
color: var(--text-color);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
header {
background-color: var(--surface-color);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 16px 0;
position: sticky;
top: 0;
z-index: 100;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-family: 'Poppins', sans-serif;
font-size: 24px;
font-weight: 700;
color: var(--primary-color);
text-decoration: none;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
nav ul li {
margin-left: 32px;
}
nav ul li a {
text-decoration: none;
color: var(--text-color);
font-weight: 600;
transition: color 0.3s ease;
}
nav ul li a:hover {
color: var(--primary-color);
}
.hero {
background: linear-gradient(45deg, var(--gradient-start), var(--gradient-end));
color: white;
padding: 120px 0;
text-align: center;
}
.hero h1 {
font-family: 'Poppins', sans-serif;
font-size: 56px;
margin: 0 0 16px;
}
.hero p {
font-size: 20px;
margin: 0 0 32px;
}
.cta-button {
font-family: 'Poppins', sans-serif;
background-color: var(--secondary-color);
color: var(--text-color);
padding: 16px 32px;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
transition: transform 0.3s ease;
display: inline-block;
}
.cta-button:hover {
transform: translateY(-2px);
}
section {
padding: 80px 0;
}
.section-title {
font-family: 'Poppins', sans-serif;
font-size: 40px;
text-align: center;
margin-bottom: 48px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 32px;
}
.card {
background-color: var(--surface-color);
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 32px;
text-align: center;
}
.testimonial-card {
background-color: var(--surface-color);
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 32px;
text-align: center;
}
.testimonial-card p {
font-style: italic;
}
.testimonial-card .author {
margin-top: 16px;
font-weight: 700;
}
#contact {
background-color: var(--surface-color);
}
form {
max-width: 600px;
margin: 0 auto;
display: flex;
flex-direction: column;
}
form input, form textarea {
font-family: 'Lato', sans-serif;
padding: 16px;
margin-bottom: 16px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 16px;
}
form button {
font-family: 'Poppins', sans-serif;
background-color: var(--primary-color);
color: white;
padding: 16px 32px;
border-radius: 8px;
border: none;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
}
form button:hover {
background-color: #228b80;
}
footer {
background-color: var(--text-color);
color: white;
text-align: center;
padding: 24px 0;
}
</style>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Style</title>
<?php
// Read project preview data from environment
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
?>
<?php if ($projectDescription): ?>
<!-- Meta description -->
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<!-- Open Graph meta tags -->
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<!-- Twitter meta tags -->
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<?php endif; ?>
<?php if ($projectImageUrl): ?>
<!-- Open Graph image -->
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<!-- Twitter image -->
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<?php endif; ?>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
</head>
<body>
<header>
<nav class="container">
<a href="#" class="logo">TAP2SKILL</a>
<ul>
<li><a href="#about">About</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#testimonials">Testimonials</a></li>
<li><a href="#contact">Contact</a></li>
<li><a href="login.php">Login</a></li>
<li><a href="register.php">Register</a></li>
</ul>
</nav>
</header>
<main>
<section class="hero">
<div class="container">
<h1>Learn. Hustle. Thrive.</h1>
<p>Your journey to mastery starts here.</p>
<a href="#features" class="cta-button">Explore Features</a>
</div>
</section>
<section id="about">
<div class="container">
<h2 class="section-title">About TAP2SKILL</h2>
<p style="text-align: center; max-width: 800px; margin: 0 auto 48px;">TAP2SKILL is a modern learning platform designed to help you acquire new skills efficiently and effectively. We believe in a hands-on, project-based approach to learning that prepares you for real-world challenges.</p>
</div>
</section>
<section id="features">
<div class="container">
<h2 class="section-title">Core Features</h2>
<div class="grid">
<div class="card">
<h3>Skill Explorer</h3>
<p>Discover new skills and learning paths tailored to your interests and career goals.</p>
</div>
<div class="card">
<h3>Video-Based Learning</h3>
<p>Engage with high-quality video content from industry experts.</p>
</div>
<div class="card">
<h3>Project-Based Tasks</h3>
<p>Apply what you learn with hands-on projects and real-world scenarios.</p>
</div>
</div>
</div>
</section>
<section id="testimonials">
<div class="container">
<h2 class="section-title">What Our Users Say</h2>
<div class="grid">
<div class="testimonial-card">
<p>"TAP2SKILL helped me land my dream job. The project-based learning was a game-changer."</p>
<p class="author">- Alex Doe</p>
</div>
<div class="testimonial-card">
<p>"I love the flexibility of the platform. I can learn at my own pace, anytime, anywhere."</p>
<p class="author">- Jane Smith</p>
</div>
<div class="testimonial-card">
<p>"The instructors are top-notch. I've learned so much in such a short time."</p>
<p class="author">- Sam Wilson</p>
</div>
</div>
</div>
</section>
<section id="contact">
<div class="container">
<h2 class="section-title">Contact Us</h2>
<form id="contact-form" action="contact.php" method="POST">
<input type="text" name="name" placeholder="Your Name" required>
<input type="email" name="email" placeholder="Your Email" required>
<textarea name="message" rows="5" placeholder="Your Message" required></textarea>
<button type="submit">Send Message</button>
</form>
</div>
</section>
</main>
<footer>
<div class="container">
<p>&copy; 2025 TAP2SKILL. All Rights Reserved.</p>
</div>
</footer>
<script>
document.getElementById('contact-form').addEventListener('submit', function(e) {
e.preventDefault();
const form = e.target;
const button = form.querySelector('button');
const buttonText = button.textContent;
button.textContent = 'Sending...';
button.disabled = true;
const formData = new FormData(form);
fetch('contact.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
form.reset();
alert('Thank you for your message! We will get back to you shortly.');
} else {
alert('An error occurred: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('An unexpected error occurred. Please try again later.');
})
.finally(() => {
button.textContent = buttonText;
button.disabled = false;
});
});
</script>
<main>
<div class="card">
<h1>Analyzing your requirements and generating your website…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
</div>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will update automatically as the plan is implemented.</p>
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
</div>
</main>
<footer>
Page updated: <?= htmlspecialchars($now) ?> (UTC)
</footer>
</body>
</html>
</html>

189
learn.php
View File

@ -1,189 +0,0 @@
<?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'];
// 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 = ?");
$stmt->execute([$skill_id]);
$skill = $stmt->fetch(PDO::FETCH_ASSOC);
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]);
$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">
<head>
<meta charset="UTF-8">
<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>
<div class="container mt-5">
<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>
<div class="mt-4">
<h3>Course Content</h3>
<div class="accordion" id="modulesAccordion">
<?php if (empty($modules)): ?>
<p><em>(Content for this course will be added soon.)</em></p>
<?php else: ?>
<?php foreach ($modules as $module): ?>
<div class="accordion-item">
<h2 class="accordion-header" id="heading<?php echo $module['id']; ?>">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse<?php echo $module['id']; ?>" aria-expanded="false" aria-controls="collapse<?php echo $module['id']; ?>">
<?php echo htmlspecialchars($module['title']); ?>
</button>
</h2>
<div id="collapse<?php echo $module['id']; ?>" class="accordion-collapse collapse" aria-labelledby="heading<?php echo $module['id']; ?>" data-bs-parent="#modulesAccordion">
<div class="accordion-body">
<?php
$lessons_stmt->execute([$module['id']]);
$lessons = $lessons_stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<?php if (empty($lessons)): ?>
<p>No lessons in this module yet.</p>
<?php else: ?>
<ul class="list-group">
<?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>
<?php endif; ?>
</div>
</div>
</div>
<?php endforeach; ?>
<?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>
</html>

232
login.php
View File

@ -1,232 +0,0 @@
<?php
session_start();
require_once __DIR__ . '/db/config.php';
$error = '';
if (isset($_SESSION['user_id'])) {
header("Location: dashboard.php");
exit;
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$email = trim($_POST['email']);
$password = $_POST['password'];
if (empty($email) || empty($password)) {
$error = 'Please fill in all fields.';
} else {
try {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
header("Location: dashboard.php");
exit;
} else {
$error = 'Invalid email or password.';
}
} catch (PDOException $e) {
$error = "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>Login - TAP2SKILL</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Lato:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #2A9D8F;
--secondary-color: #E9C46A;
--background-color: #F4F4F4;
--surface-color: #FFFFFF;
--text-color: #264653;
--error-color: #e74c3c;
--success-color: #2ecc71;
}
body {
font-family: 'Lato', sans-serif;
margin: 0;
background-color: var(--background-color);
color: var(--text-color);
display: flex;
flex-direction: column;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
header {
background-color: var(--surface-color);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 16px 0;
position: sticky;
top: 0;
z-index: 100;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-family: 'Poppins', sans-serif;
font-size: 24px;
font-weight: 700;
color: var(--primary-color);
text-decoration: none;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
nav ul li {
margin-left: 32px;
}
nav ul li a {
text-decoration: none;
color: var(--text-color);
font-weight: 600;
transition: color 0.3s ease;
}
nav ul li a:hover {
color: var(--primary-color);
}
main {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 80px 0;
}
.form-container {
background-color: var(--surface-color);
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 48px;
width: 100%;
max-width: 480px;
}
.form-title {
font-family: 'Poppins', sans-serif;
font-size: 32px;
text-align: center;
margin-bottom: 32px;
}
form input {
font-family: 'Lato', sans-serif;
padding: 16px;
margin-bottom: 16px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 16px;
width: 100%;
box-sizing: border-box;
}
form button {
font-family: 'Poppins', sans-serif;
background-color: var(--primary-color);
color: white;
padding: 16px 32px;
border-radius: 8px;
border: none;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
width: 100%;
font-size: 16px;
}
form button:hover {
background-color: #228b80;
}
.alert-message {
color: white;
padding: 16px;
border-radius: 8px;
text-align: center;
margin-bottom: 16px;
}
.alert-message.error {
background-color: var(--error-color);
}
.alert-message.success {
background-color: var(--success-color);
}
.form-footer {
text-align: center;
margin-top: 24px;
}
.form-footer a {
color: var(--primary-color);
text-decoration: none;
font-weight: 600;
}
footer {
background-color: var(--text-color);
color: white;
text-align: center;
padding: 24px 0;
}
</style>
</head>
<body>
<header>
<nav class="container">
<a href="index.php" class="logo">TAP2SKILL</a>
<ul>
<li><a href="index.php#about">About</a></li>
<li><a href="index.php#features">Features</a></li>
<li><a href="index.php#testimonials">Testimonials</a></li>
<li><a href="index.php#contact">Contact</a></li>
<li><a href="register.php">Register</a></li>
</ul>
</nav>
</header>
<main>
<div class="form-container">
<h2 class="form-title">Login</h2>
<?php if (isset($_GET['registered'])): ?>
<div class="alert-message success">Registration successful! Please log in.</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert-message error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form action="login.php" method="post">
<input type="email" name="email" placeholder="Email Address" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
<div class="form-footer">
<p>Don't have an account? <a href="register.php">Register here</a>.</p>
</div>
</div>
</main>
<footer>
<div class="container">
<p>&copy; 2025 TAP2SKILL. All Rights Reserved.</p>
</div>
</footer>
</body>
</html>

View File

@ -1,6 +0,0 @@
<?php
session_start();
session_unset();
session_destroy();
header("Location: login.php");
exit;

108
quiz.php
View File

@ -1,108 +0,0 @@
<?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>

View File

@ -1,226 +0,0 @@
<?php
require_once __DIR__ . '/db/config.php';
$error = '';
$success = '';
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = $_POST['password'];
if (empty($username) || empty($email) || empty($password)) {
$error = 'Please fill in all fields.';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = 'Invalid email format.';
} else {
try {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username OR email = :email");
$stmt->execute(['username' => $username, 'email' => $email]);
if ($stmt->fetch()) {
$error = 'Username or email already exists.';
} else {
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$insert_stmt = $pdo->prepare("INSERT INTO users (username, email, password) VALUES (:username, :email, :password)");
$insert_stmt->execute([
'username' => $username,
'email' => $email,
'password' => $hashed_password
]);
header("Location: login.php?registered=true");
exit;
}
} catch (PDOException $e) {
$error = "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>Register - TAP2SKILL</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Lato:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #2A9D8F;
--secondary-color: #E9C46A;
--background-color: #F4F4F4;
--surface-color: #FFFFFF;
--text-color: #264653;
--error-color: #e74c3c;
}
body {
font-family: 'Lato', sans-serif;
margin: 0;
background-color: var(--background-color);
color: var(--text-color);
display: flex;
flex-direction: column;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
header {
background-color: var(--surface-color);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 16px 0;
position: sticky;
top: 0;
z-index: 100;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-family: 'Poppins', sans-serif;
font-size: 24px;
font-weight: 700;
color: var(--primary-color);
text-decoration: none;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
nav ul li {
margin-left: 32px;
}
nav ul li a {
text-decoration: none;
color: var(--text-color);
font-weight: 600;
transition: color 0.3s ease;
}
nav ul li a:hover {
color: var(--primary-color);
}
main {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 80px 0;
}
.form-container {
background-color: var(--surface-color);
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 48px;
width: 100%;
max-width: 480px;
}
.form-title {
font-family: 'Poppins', sans-serif;
font-size: 32px;
text-align: center;
margin-bottom: 32px;
}
form input {
font-family: 'Lato', sans-serif;
padding: 16px;
margin-bottom: 16px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 16px;
width: 100%;
box-sizing: border-box;
}
form button {
font-family: 'Poppins', sans-serif;
background-color: var(--primary-color);
color: white;
padding: 16px 32px;
border-radius: 8px;
border: none;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
width: 100%;
font-size: 16px;
}
form button:hover {
background-color: #228b80;
}
.error-message {
background-color: var(--error-color);
color: white;
padding: 16px;
border-radius: 8px;
text-align: center;
margin-bottom: 16px;
}
.form-footer {
text-align: center;
margin-top: 24px;
}
.form-footer a {
color: var(--primary-color);
text-decoration: none;
font-weight: 600;
}
footer {
background-color: var(--text-color);
color: white;
text-align: center;
padding: 24px 0;
}
</style>
</head>
<body>
<header>
<nav class="container">
<a href="index.php" class="logo">TAP2SKILL</a>
<ul>
<li><a href="index.php#about">About</a></li>
<li><a href="index.php#features">Features</a></li>
<li><a href="index.php#testimonials">Testimonials</a></li>
<li><a href="index.php#contact">Contact</a></li>
<li><a href="login.php">Login</a></li>
</ul>
</nav>
</header>
<main>
<div class="form-container">
<h2 class="form-title">Create Account</h2>
<?php if ($error): ?>
<div class="error-message"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form action="register.php" method="post">
<input type="text" name="username" placeholder="Username" required>
<input type="email" name="email" placeholder="Email Address" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Register</button>
</form>
<div class="form-footer">
<p>Already have an account? <a href="login.php">Login here</a>.</p>
</div>
</div>
</main>
<footer>
<div class="container">
<p>&copy; 2025 TAP2SKILL. All Rights Reserved.</p>
</div>
</footer>
</body>
</html>