mirror of
https://github.com/myronblair/tomsjavajive-app
synced 2026-06-30 09:40:59 -05:00
253 lines
12 KiB
PHP
253 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Tom's Java Jive - Product Detail Page
|
|
*/
|
|
|
|
require_once __DIR__ . '/includes/functions.php';
|
|
|
|
$productId = $_GET['id'] ?? '';
|
|
|
|
if (!$productId) {
|
|
header('Location: /shop.php');
|
|
exit;
|
|
}
|
|
|
|
// Get product
|
|
$product = db()->fetch(
|
|
"SELECT * FROM products WHERE product_id = :id AND is_active = 1",
|
|
['id' => $productId]
|
|
);
|
|
|
|
if (!$product) {
|
|
header('Location: /shop.php');
|
|
exit;
|
|
}
|
|
|
|
$pageTitle = $product['name'] . " - Tom's Java Jive";
|
|
$pageDescription = truncate(strip_tags($product['description']), 160);
|
|
|
|
// Get product reviews
|
|
$reviews = db()->fetchAll(
|
|
"SELECT * FROM reviews WHERE product_id = :id AND is_approved = 1 ORDER BY created_at DESC LIMIT 10",
|
|
['id' => $productId]
|
|
);
|
|
|
|
$avgRating = 0;
|
|
$reviewCount = count($reviews);
|
|
if ($reviewCount > 0) {
|
|
$avgRating = array_sum(array_column($reviews, 'rating')) / $reviewCount;
|
|
}
|
|
|
|
// Get related products
|
|
$relatedProducts = db()->fetchAll(
|
|
"SELECT * FROM products WHERE category = :category AND product_id != :id AND is_active = 1 LIMIT 4",
|
|
['category' => $product['category'], 'id' => $productId]
|
|
);
|
|
|
|
$images = json_decode($product['images'] ?? '[]', true);
|
|
$mainImage = !empty($images) ? $images[0] : '/assets/images/placeholder-product.svg';
|
|
$salePrice = $product['sale_price'];
|
|
$price = $product['price'];
|
|
$inStock = $product['stock'] > 0;
|
|
|
|
require_once __DIR__ . '/includes/header.php';
|
|
?>
|
|
|
|
<section class="section" style="padding-top: 2rem;">
|
|
<div class="container">
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: start;">
|
|
|
|
<!-- Product Images -->
|
|
<div>
|
|
<div class="product-main-image" style="border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 1rem;">
|
|
<img src="<?= htmlspecialchars($mainImage) ?>" alt="<?= htmlspecialchars($product['name']) ?>"
|
|
id="mainImage" style="width: 100%; aspect-ratio: 1; object-fit: cover;">
|
|
</div>
|
|
|
|
<?php if (count($images) > 1): ?>
|
|
<div style="display: flex; gap: 0.5rem; overflow-x: auto;">
|
|
<?php foreach ($images as $index => $img): ?>
|
|
<img src="<?= htmlspecialchars($img) ?>" alt="Product image <?= $index + 1 ?>"
|
|
onclick="document.getElementById('mainImage').src='<?= htmlspecialchars($img) ?>'"
|
|
style="width: 80px; height: 80px; object-fit: cover; border-radius: var(--radius-md); cursor: pointer; border: 2px solid transparent;"
|
|
class="thumbnail">
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Product Info -->
|
|
<div>
|
|
<?php if ($product['category']): ?>
|
|
<p class="text-muted mb-1">
|
|
<a href="/shop.php?category=<?= urlencode($product['category']) ?>">
|
|
<?= htmlspecialchars(ucfirst($product['category'])) ?>
|
|
</a>
|
|
</p>
|
|
<?php endif; ?>
|
|
|
|
<h1 style="margin-bottom: 0.5rem;"><?= htmlspecialchars($product['name']) ?></h1>
|
|
|
|
<!-- Rating -->
|
|
<?php if ($reviewCount > 0): ?>
|
|
<div style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1rem;">
|
|
<div class="stars" style="color: #F59E0B;">
|
|
<?php for ($i = 1; $i <= 5; $i++): ?>
|
|
<i class="fa<?= $i <= round($avgRating) ? 's' : 'r' ?> fa-star"></i>
|
|
<?php endfor; ?>
|
|
</div>
|
|
<span class="text-muted">(<?= $reviewCount ?> reviews)</span>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Price -->
|
|
<div class="product-price" style="font-size: 1.5rem; margin-bottom: 1.5rem;">
|
|
<?php if ($salePrice && $salePrice < $price): ?>
|
|
<span class="current"><?= formatCurrency($salePrice) ?></span>
|
|
<span class="original"><?= formatCurrency($price) ?></span>
|
|
<span style="background: var(--color-error); color: white; padding: 0.25rem 0.5rem; border-radius: var(--radius-sm); font-size: 0.875rem; margin-left: 0.5rem;">
|
|
Save <?= round((($price - $salePrice) / $price) * 100) ?>%
|
|
</span>
|
|
<?php else: ?>
|
|
<span class="current"><?= formatCurrency($price) ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Stock Status -->
|
|
<p style="margin-bottom: 1rem;">
|
|
<?php if ($inStock): ?>
|
|
<span style="color: var(--color-success);"><i class="fas fa-check-circle"></i> In Stock</span>
|
|
<?php if ($product['stock'] <= 10): ?>
|
|
<span class="text-muted"> - Only <?= $product['stock'] ?> left!</span>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<span style="color: var(--color-error);"><i class="fas fa-times-circle"></i> Out of Stock</span>
|
|
<?php endif; ?>
|
|
</p>
|
|
|
|
<!-- Add to Cart Form -->
|
|
<?php if ($inStock): ?>
|
|
<form id="add-to-cart-form" style="margin-bottom: 2rem;">
|
|
<div style="display: flex; gap: 1rem; align-items: center; margin-bottom: 1rem;">
|
|
<div class="quantity-selector" style="display: flex; align-items: center; border: 1px solid var(--color-border); border-radius: var(--radius-md);">
|
|
<button type="button" class="qty-minus btn" style="padding: 0.5rem 1rem;">-</button>
|
|
<input type="number" class="qty-input" value="1" min="1" max="<?= $product['stock'] ?>"
|
|
style="width: 60px; text-align: center; border: none; outline: none;">
|
|
<button type="button" class="qty-plus btn" style="padding: 0.5rem 1rem;">+</button>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-primary btn-lg add-to-cart-btn"
|
|
data-product-id="<?= $product['product_id'] ?>"
|
|
onclick="addToCart('<?= $product['product_id'] ?>', document.querySelector('.qty-input').value)">
|
|
<i class="fas fa-shopping-bag"></i> Add to Cart
|
|
</button>
|
|
</form>
|
|
<?php else: ?>
|
|
<button class="btn btn-secondary btn-lg" disabled style="margin-bottom: 2rem;">
|
|
Out of Stock
|
|
</button>
|
|
<?php endif; ?>
|
|
|
|
<!-- Description -->
|
|
<div style="margin-bottom: 2rem;">
|
|
<h3 style="margin-bottom: 0.5rem;">Description</h3>
|
|
<div class="text-muted">
|
|
<?= nl2br(htmlspecialchars($product['description'])) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Product Details -->
|
|
<div style="background: var(--color-background); padding: 1rem; border-radius: var(--radius-md);">
|
|
<h4 style="margin-bottom: 0.5rem;">Product Details</h4>
|
|
<table style="width: 100%;">
|
|
<?php if ($product['sku']): ?>
|
|
<tr>
|
|
<td class="text-muted">SKU</td>
|
|
<td><?= htmlspecialchars($product['sku']) ?></td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<?php if ($product['weight']): ?>
|
|
<tr>
|
|
<td class="text-muted">Weight</td>
|
|
<td><?= $product['weight'] ?> oz</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<tr>
|
|
<td class="text-muted">Category</td>
|
|
<td><?= htmlspecialchars(ucfirst($product['category'] ?? 'General')) ?></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Reviews Section -->
|
|
<div style="margin-top: 3rem;">
|
|
<h2 style="margin-bottom: 1.5rem;">Customer Reviews</h2>
|
|
|
|
<?php if (!empty($reviews)): ?>
|
|
<div style="display: grid; gap: 1rem;">
|
|
<?php foreach ($reviews as $review): ?>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 0.5rem;">
|
|
<div>
|
|
<strong><?= htmlspecialchars($review['customer_name']) ?></strong>
|
|
<?php if ($review['is_verified_purchase']): ?>
|
|
<span style="color: var(--color-success); font-size: 0.875rem;">
|
|
<i class="fas fa-check-circle"></i> Verified Purchase
|
|
</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<span class="text-muted"><?= formatDate($review['created_at']) ?></span>
|
|
</div>
|
|
<div class="stars" style="color: #F59E0B; margin-bottom: 0.5rem;">
|
|
<?php for ($i = 1; $i <= 5; $i++): ?>
|
|
<i class="fa<?= $i <= $review['rating'] ? 's' : 'r' ?> fa-star"></i>
|
|
<?php endfor; ?>
|
|
</div>
|
|
<?php if ($review['title']): ?>
|
|
<h4 style="margin-bottom: 0.25rem;"><?= htmlspecialchars($review['title']) ?></h4>
|
|
<?php endif; ?>
|
|
<p class="text-muted mb-0"><?= nl2br(htmlspecialchars($review['comment'])) ?></p>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<p class="text-muted">No reviews yet. Be the first to review this product!</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Related Products -->
|
|
<?php if (!empty($relatedProducts)): ?>
|
|
<div style="margin-top: 3rem;">
|
|
<h2 style="margin-bottom: 1.5rem;">Related Products</h2>
|
|
<div class="product-grid">
|
|
<?php foreach ($relatedProducts as $related):
|
|
$relImages = json_decode($related['images'] ?? '[]', true);
|
|
$relImageUrl = !empty($relImages) ? $relImages[0] : '/assets/images/placeholder-product.svg';
|
|
?>
|
|
<div class="product-card">
|
|
<a href="/product.php?id=<?= $related['product_id'] ?>">
|
|
<div class="product-image">
|
|
<img src="<?= htmlspecialchars($relImageUrl) ?>" alt="<?= htmlspecialchars($related['name']) ?>">
|
|
</div>
|
|
<div class="product-info">
|
|
<h3 class="product-name"><?= htmlspecialchars($related['name']) ?></h3>
|
|
<div class="product-price">
|
|
<span class="current"><?= formatCurrency($related['sale_price'] ?? $related['price']) ?></span>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</section>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|