36735-vm/index.php
Flatlogic Bot d076708932 feat: Implement new design and features for the main page
- Redesigned the main page with a modern look and feel.
- Added search and filtering functionality for drills.
- Implemented pagination for browsing drills.
- Added the ability for users to mark drills as favorites.
2025-12-07 18:15:23 +00:00

256 lines
12 KiB
PHP

<?php
require_once __DIR__ . '/partials/header.php';
require_once 'db/config.php';
require_once 'auth.php';
// Pagination settings
$drillsPerPage = 9;
$currentPage = isset($_GET['page']) ? (int)$_GET['page'] : 1;
if ($currentPage < 1) {
$currentPage = 1;
}
$offset = ($currentPage - 1) * $drillsPerPage;
// Fetch drills from the database
try {
$pdo = db();
// Base query for counting total matching drills
$userId = $_SESSION['user_id'] ?? 0;
// Base query for counting total matching drills
$countSql = "SELECT COUNT(d.id) FROM drills d WHERE d.is_public = TRUE";
// Base query for fetching drills with favorite status
$sql = "SELECT d.*, CASE WHEN uf.user_id IS NOT NULL THEN 1 ELSE 0 END AS is_favorite
FROM drills d
LEFT JOIN user_favorites uf ON d.id = uf.drill_id AND uf.user_id = :userId
WHERE d.is_public = TRUE";
$params = [];
// Search functionality
$searchTerm = $_GET['search'] ?? '';
if (!empty($searchTerm)) {
$filterCondition = " AND (title LIKE ? OR description LIKE ?)";
$countSql .= $filterCondition;
$sql .= $filterCondition;
$params[] = "%" . $searchTerm . "%";
$params[] = "%" . $searchTerm . "%";
}
// Filter functionality
$ageGroup = $_GET['age_group'] ?? '';
if (!empty($ageGroup)) {
$filterCondition = " AND age_group = ?";
$countSql .= $filterCondition;
$sql .= $filterCondition;
$params[] = $ageGroup;
}
$difficulty = $_GET['difficulty'] ?? '';
if (!empty($difficulty)) {
$filterCondition = " AND difficulty = ?";
$countSql .= $filterCondition;
$sql .= $filterCondition;
$params[] = $difficulty;
}
// Get total number of drills that match filters
$countStmt = $pdo->prepare($countSql);
$countStmt->execute($params);
$totalDrills = $countStmt->fetchColumn();
$totalPages = ceil($totalDrills / $drillsPerPage);
// Add ordering and pagination to the main query
$sql .= " ORDER BY created_at DESC LIMIT :limit OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':userId', $userId, PDO::PARAM_INT);
// Bind filter parameters
foreach ($params as $key => $value) {
$stmt->bindValue($key + 1, $value);
}
// Bind pagination parameters
$stmt->bindValue(':limit', $drillsPerPage, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$drills = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Fetch distinct filter values for dropdowns
$ageGroups = $pdo->query("SELECT DISTINCT age_group FROM drills WHERE is_public = TRUE ORDER BY age_group")->fetchAll(PDO::FETCH_COLUMN);
$difficulties = $pdo->query("SELECT DISTINCT difficulty FROM drills WHERE is_public = TRUE ORDER BY difficulty")->fetchAll(PDO::FETCH_COLUMN);
} catch (PDOException $e) {
// For production, you would log this error and show a generic error page.
die("Error fetching drills: " . $e->getMessage());
}
?>
<header class="py-5 text-center container-fluid">
<div class="row py-lg-5">
<div class="col-lg-6 col-md-8 mx-auto">
<h1 class="display-4 fw-bold">Find Your Perfect Drill</h1>
<p class="lead text-muted"><?php echo htmlspecialchars($pageDescription); ?></p>
<p>
<a href="create_drill.php" class="btn btn-primary my-2">Create a Drill</a>
<a href="#" class="btn btn-secondary my-2">Browse All</a>
</p>
</div>
</div>
</header>
<main class="container">
<!-- Search and Filter Form -->
<div class="mb-5 p-4 rounded-3 shadow-sm bg-light">
<form action="index.php" method="GET" class="row g-3 align-items-end">
<div class="col-md-5">
<label for="search" class="form-label">Search</label>
<input type="text" class="form-control" id="search" name="search" placeholder="e.g., Passing, Dribbling..." value="<?php echo htmlspecialchars($searchTerm); ?>">
</div>
<div class="col-md-3">
<label for="age_group" class="form-label">Age Group</label>
<select id="age_group" name="age_group" class="form-select">
<option value="">All Ages</option>
<?php foreach ($ageGroups as $ag): ?>
<option value="<?php echo htmlspecialchars($ag); ?>" <?php echo ($ageGroup === $ag) ? 'selected' : ''; ?>><?php echo htmlspecialchars($ag); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label for="difficulty" class="form-label">Difficulty</label>
<select id="difficulty" name="difficulty" class="form-select">
<option value="">All</option>
<?php foreach ($difficulties as $d): ?>
<option value="<?php echo htmlspecialchars($d); ?>" <?php echo ($difficulty === $d) ? 'selected' : ''; ?>><?php echo htmlspecialchars($d); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">Filter</button>
</div>
</form>
</div>
<h2 class="mb-4">All Drills</h2>
<!-- Drills Grid -->
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-4">
<?php if (empty($drills)): ?>
<div class="col-12">
<div class="alert alert-info text-center">No drills found matching your criteria.</div>
</div>
<?php else: ?>
<?php foreach ($drills as $drill): ?>
<div class="col">
<div class="card h-100 card-drill shadow-sm">
<?php if (!empty($drill['image_path'])) : ?>
<img src="<?php echo htmlspecialchars($drill['image_path']); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($drill['title']); ?>" style="height: 200px; object-fit: cover;">
<?php elseif (!empty($drill['youtube_url']) && get_youtube_id_from_url($drill['youtube_url'])) : ?>
<div class="card-img-top ratio ratio-16x9">
<iframe style="min-height: 200px;" src="https://www.youtube.com/embed/<?php echo get_youtube_id_from_url($drill['youtube_url']); ?>?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div>
<?php else : ?>
<svg class="card-img-top bg-light" width="100%" height="200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Image" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="var(--light-gray)"></rect><text x="50%" y="50%" fill="var(--text-color)" dy=".3em">No Image</text></svg>
<?php endif; ?>
<div class="card-body">
<h5 class="card-title fw-bold"><?php echo htmlspecialchars($drill['title']); ?></h5>
<p class="card-text text-muted"><?php echo htmlspecialchars(substr($drill['description'], 0, 80)); ?>...</p>
</div>
<div class="card-footer bg-transparent border-top-0 d-flex justify-content-between align-items-center">
<a href="drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-sm btn-outline-primary">View Details</a>
<div class="d-flex align-items-center">
<?php if (is_logged_in()): ?>
<span class="favorite-icon material-icons-outlined me-2 <?php echo $drill['is_favorite'] ? 'is-favorite' : ''; ?>" data-drill-id="<?php echo $drill['id']; ?>">
<?php echo $drill['is_favorite'] ? 'favorite' : 'favorite_border'; ?>
</span>
<?php endif; ?>
<span class="badge bg-light text-dark me-1"><?php echo htmlspecialchars($drill['age_group']); ?></span>
<span class="badge
<?php
switch (strtolower($drill['difficulty'])) {
case 'easy': echo 'bg-success'; break;
case 'medium': echo 'bg-warning text-dark'; break;
case 'hard': echo 'bg-danger'; break;
default: echo 'bg-secondary';
}
?>">
<?php echo htmlspecialchars($drill['difficulty']); ?>
</span>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<!-- Pagination -->
<?php if ($totalPages > 1) : ?>
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
<?php
// Build the query string for pagination links
$queryParams = $_GET;
unset($queryParams['page']);
$queryString = http_build_query($queryParams);
?>
<!-- Previous Page -->
<li class="page-item <?php echo ($currentPage <= 1) ? 'disabled' : ''; ?>">
<a class="page-link" href="?page=<?php echo $currentPage - 1; ?>&<?php echo $queryString; ?>" tabindex="-1" aria-disabled="true">Previous</a>
</li>
<!-- Page Numbers -->
<?php for ($i = 1; $i <= $totalPages; $i++) : ?>
<li class="page-item <?php echo ($i === $currentPage) ? 'active' : ''; ?>">
<a class="page-link" href="?page=<?php echo $i; ?>&<?php echo $queryString; ?>"><?php echo $i; ?></a>
</li>
<?php endfor; ?>
<!-- Next Page -->
<li class="page-item <?php echo ($currentPage >= $totalPages) ? 'disabled' : ''; ?>">
<a class="page-link" href="?page=<?php echo $currentPage + 1; ?>&<?php echo $queryString; ?>">Next</a>
</li>
</ul>
</nav>
<?php endif; ?>
</main>
<script>
document.addEventListener('DOMContentLoaded', function () {
const favoriteIcons = document.querySelectorAll('.favorite-icon');
favoriteIcons.forEach(icon => {
icon.addEventListener('click', function () {
const drillId = this.dataset.drillId;
const isFavorited = this.textContent.trim() === 'favorite';
fetch('toggle_favorite.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `drill_id=${drillId}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
this.textContent = isFavorited ? 'favorite_border' : 'favorite';
} else {
console.error('Failed to toggle favorite');
}
})
.catch(error => console.error('Error:', error));
});
});
});
</script>
<?php require_once __DIR__ . '/partials/footer.php'; ?>