| Server IP : 3.111.61.48 / Your IP : 216.73.216.67 Web Server : Apache System : Linux ip-10-0-5-176 6.8.0-1057-aws #60~22.04.1-Ubuntu SMP Wed May 27 08:16:59 UTC 2026 x86_64 User : ubuntu ( 1000) PHP Version : 8.2.31 Disable Function : exec,passthru,shell_exec,system MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/vhost/book.gyaniguru.org/ |
Upload File : |
<?php
session_start();
require_once 'includes/db.php';
function eurl($url) {
$parts = explode('/', $url);
$fn = array_pop($parts);
return ($parts ? implode('/', $parts) . '/' : '') . rawurlencode($fn);
}
$id = $_GET['id'] ?? 0;
$book = get_row("SELECT b.*, c.name as cat_name, c.slug as cat_slug FROM books b LEFT JOIN categories c ON b.category_id = c.id WHERE b.id = ?", [$id]);
if (!$book) {
header("Location: shop.php");
exit();
}
$page_title = $book['title'];
include 'includes/header.php';
// Fetch additional images
$all_images = [];
$all_images[] = $book['image'];
$additional_images = get_all("SELECT image_url FROM book_images WHERE book_id = ? ORDER BY sort_order", [$id]);
foreach($additional_images as $img) {
if($img['image_url'] != $book['image']) {
$all_images[] = $img['image_url'];
}
}
$total_images = count($all_images);
// Fetch related books (same category, excluding current)
$related = get_all("SELECT * FROM books WHERE category_id = ? AND id != ? LIMIT 4", [$book['category_id'], $id]);
if (count($related) < 4) {
$more = get_all("SELECT * FROM books WHERE id != ? ORDER BY RAND() LIMIT ?", [$id, 4 - count($related)]);
$related = array_merge($related, $more);
}
// Fetch reviews
$reviews = get_all("SELECT r.*, u.name as user_name FROM reviews r JOIN users u ON r.user_id = u.id WHERE r.book_id = ? AND r.status = 'approved' ORDER BY r.created_at DESC", [$id]);
$review_count = count($reviews);
$avg_rating = 0;
$filled = 0;
$half = false;
$rating_distribution = [1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0];
if ($review_count > 0) {
$total = 0;
foreach ($reviews as $rv) {
$total += $rv['rating'];
$rating_distribution[$rv['rating']]++;
}
$avg_rating = round($total / $review_count, 1);
$filled = floor($avg_rating);
$half = ($avg_rating - $filled) >= 0.5;
}
$user_review = null;
if (isset($_SESSION['user_id'])) {
$user_review = get_row("SELECT * FROM reviews WHERE book_id = ? AND user_id = ?", [$id, $_SESSION['user_id']]);
}
?>
<style>
.book-detail-page { background: #f8f7f4; min-height: 100vh; }
/* ── Gallery ── */
.book-gallery-wrap { position: sticky; top: 100px; }
.fk-gallery {
background: #fff; border-radius: 16px;
box-shadow: 0 4px 24px rgba(0,0,0,0.06);
overflow: hidden; position: relative;
}
.fk-main-img {
position: relative; width: 100%;
padding-top: 133%;
background: #fafafa; cursor: crosshair; overflow: hidden;
}
.fk-main-img img {
position: absolute; inset: 0; width: 100%; height: 100%;
object-fit: contain; transition: opacity .3s; padding: 24px;
}
.fk-lens {
position: absolute; width: 120px; height: 120px;
border: 2px solid var(--gold); background: rgba(255,255,255,.25);
pointer-events: none; display: none; z-index: 5; border-radius: 50%;
}
.fk-zoom-result {
position: absolute; top: 0; left: calc(100% + 16px);
width: 420px; height: 560px; background-repeat: no-repeat;
border: 2px solid var(--gold); border-radius: 12px;
box-shadow: 0 12px 40px rgba(0,0,0,.18); z-index: 10; display: none;
background-color: #fff;
}
.fk-thumbs {
display: flex; gap: 8px; padding: 14px 16px;
background: #fff; border-top: 1px solid #f0f0f0;
overflow-x: auto; scroll-behavior: smooth;
}
.fk-thumbs::-webkit-scrollbar { height: 3px; }
.fk-thumbs::-webkit-scrollbar-thumb { background: var(--gold); border-radius: 4px; }
.fk-thumbs::-webkit-scrollbar-track { background: #eee; }
.fk-thumb {
flex: 0 0 72px; width: 72px; height: 72px;
border: 2px solid #e0e0e0; border-radius: 8px; overflow: hidden;
cursor: pointer; transition: all .2s; background: #fafafa; padding: 4px;
}
.fk-thumb:hover { border-color: var(--gold-dark); }
.fk-thumb.active { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold); }
.fk-thumb img { width: 100%; height: 100%; object-fit: contain; }
.wishlist-float {
position: absolute; top: 16px; right: 16px; z-index: 6;
width: 44px; height: 44px; border-radius: 50%; border: none;
background: rgba(255,255,255,.92); color: var(--text-light);
font-size: 1.2rem; cursor: pointer;
box-shadow: 0 2px 12px rgba(0,0,0,.12);
transition: all .25s; display: flex; align-items: center; justify-content: center;
}
.wishlist-float:hover { transform: scale(1.1); color: var(--maroon); }
.wishlist-float.active { color: var(--maroon); background: #fff5f5; }
/* ── Details ── */
.detail-section { padding-left: 0; }
@media (min-width: 992px) { .detail-section { padding-left: 16px; } }
.badge-category {
display: inline-flex; align-items: center; gap: 6px;
background: rgba(212,175,55,.12); color: var(--gold-dark);
border: 1px solid rgba(212,175,55,.35); border-radius: 50px;
padding: 5px 16px; font-size: .78rem; font-weight: 600;
letter-spacing: .5px; text-transform: uppercase;
}
.book-title-detail {
font-family: 'Inter', sans-serif;
font-weight: 800;
font-size: clamp(1.4rem, 2.5vw, 2rem);
color: var(--maroon); line-height: 1.25; margin-bottom: 4px;
}
.book-title-bengali {
font-size: clamp(1.1rem, 1.8vw, 1.4rem);
color: var(--gerua-deep); font-weight: 600; margin-bottom: 20px;
}
.author-row {
display: flex; align-items: center; gap: 14px;
padding: 16px 20px; background: #fff; border-radius: 14px;
box-shadow: 0 1px 6px rgba(0,0,0,.04); margin-bottom: 20px;
}
.author-avatar-detail {
width: 52px; height: 52px; border-radius: 50%;
background: var(--gradient-saffron); display: flex;
align-items: center; justify-content: center;
font-size: 1.4rem; color: #fff; flex-shrink: 0;
}
.author-meta { flex: 1; }
.author-meta .label { font-size: .72rem; color: var(--text-light); text-transform: uppercase; letter-spacing: 1px; }
.author-meta .name { font-weight: 700; font-size: 1rem; color: var(--text-dark); }
.rating-stars { color: var(--gold); font-size: .9rem; }
.rating-text { font-size: .8rem; color: var(--text-light); }
/* ── Price card ── */
.price-card-detail {
background: #fff; border-radius: 16px; padding: 24px;
box-shadow: 0 2px 16px rgba(0,0,0,.04);
border: 1px solid rgba(212,175,55,.12);
margin-bottom: 20px;
}
.price-row { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.price-current { font-size: 2rem; font-weight: 800; color: var(--maroon-light); line-height: 1; }
.price-original { font-size: 1.1rem; color: var(--text-light); text-decoration: line-through; }
.price-badge {
background: linear-gradient(135deg, #e74c3c, #c0392b);
color: #fff; font-weight: 700; font-size: .82rem;
padding: 3px 14px; border-radius: 50px;
}
.price-offer-row {
display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px;
}
.offer-tag {
display: inline-flex; align-items: center; gap: 6px;
background: #f0fff4; color: #2f855a; font-size: .78rem;
padding: 5px 12px; border-radius: 8px; font-weight: 500;
border: 1px solid #c6f6d5;
}
.offer-tag i { font-size: .85rem; }
.stock-badge {
color: #2f855a; font-weight: 600; font-size: .85rem;
margin-top: 10px; display: flex; align-items: center; gap: 6px;
}
.stock-badge i { font-size: 1rem; }
/* ── Highlights ── */
.highlights-bar {
display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 10px; margin-bottom: 24px;
}
.highlight-item {
background: #fff; border-radius: 12px; padding: 14px 12px;
text-align: center; border: 1px solid #f0ede8;
transition: transform .2s;
}
.highlight-item:hover { transform: translateY(-2px); }
.highlight-item i { font-size: 1.3rem; color: var(--gold); display: block; margin-bottom: 4px; }
.highlight-item .val { font-weight: 700; font-size: .85rem; color: var(--text-dark); display: block; }
.highlight-item .lbl { font-size: .68rem; color: var(--text-light); text-transform: uppercase; letter-spacing: .5px; }
/* ── Description ── */
.desc-wrap {
background: #fff; border-radius: 16px; padding: 24px;
box-shadow: 0 2px 16px rgba(0,0,0,.04);
margin-bottom: 24px; line-height: 1.8; color: var(--text-medium);
font-size: .95rem;
}
.desc-wrap h5 {
font-family: 'Inter', sans-serif;
font-weight: 700;
color: var(--maroon); margin-bottom: 12px;
}
/* ── Specs grid ── */
.specs-grid {
display: grid; grid-template-columns: repeat(3,1fr); gap: 10px;
margin-bottom: 24px;
}
.spec-card {
background: #fff; border-radius: 14px; padding: 18px 14px;
text-align: center; border: 1px solid #f0ede8;
transition: all .2s;
}
.spec-card:hover { border-color: rgba(212,175,55,.3); box-shadow: 0 4px 16px rgba(0,0,0,.04); }
.spec-card i { font-size: 1.4rem; color: var(--gold); display: block; margin-bottom: 6px; }
.spec-card .lbl { font-size: .65rem; color: var(--text-light); text-transform: uppercase; letter-spacing: .5px; display: block; }
.spec-card .val { font-weight: 700; font-size: .9rem; color: var(--text-dark); }
/* ── Qty + Actions ── */
.action-bar {
display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 20px;
}
.action-bar .qty-group {
display: flex; align-items: center; background: #fff;
border: 1.5px solid #e0ddd8; border-radius: 10px; overflow: hidden;
flex-shrink: 0;
}
.action-bar .qty-group button {
width: 42px; height: 42px; border: none; background: transparent;
color: var(--text-dark); font-size: 1.05rem; cursor: pointer;
transition: background .2s; display: flex; align-items: center; justify-content: center;
}
.action-bar .qty-group button:hover { background: var(--cream); }
.action-bar .qty-group input {
width: 44px; height: 42px; border: none; text-align: center;
font-weight: 700; font-size: 1rem; background: #fff;
border-left: 1.5px solid #e0ddd8; border-right: 1.5px solid #e0ddd8;
color: var(--text-dark);
}
.action-bar .qty-group input:focus { outline: none; }
.action-bar .btn-group {
display: flex; gap: 10px; flex: 1; min-width: 0;
}
.action-bar .btn-add-cart,
.action-bar .btn-buy-now {
flex: 1; height: 48px; border: none; border-radius: 10px;
font-weight: 700; font-size: .88rem; letter-spacing: .5px;
transition: all .25s; display: flex; align-items: center; justify-content: center; gap: 8px;
white-space: nowrap; padding: 0 12px;
}
.action-bar .btn-add-cart {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
color: #fff; box-shadow: 0 4px 14px rgba(245,158,11,.35);
}
.action-bar .btn-add-cart:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(245,158,11,.45);
}
.action-bar .btn-buy-now {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: #fff; box-shadow: 0 4px 14px rgba(16,185,129,.35);
}
.action-bar .btn-buy-now:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(16,185,129,.45);
}
@media (max-width: 575px) {
.action-bar .qty-group { width: 100%; }
.action-bar .qty-group button,
.action-bar .qty-group input { height: 48px; }
.action-bar .qty-group input { flex: 1; width: auto; }
.action-bar .btn-group { width: 100%; }
.action-bar .btn-add-cart,
.action-bar .btn-buy-now { height: 52px; font-size: .85rem; }
}
/* ── Trust strip ── */
.trust-strip {
display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 20px;
}
.trust-item {
display: flex; align-items: center; gap: 8px;
font-size: .82rem; color: var(--text-medium);
}
.trust-item i { color: var(--gold); font-size: 1rem; }
/* ── Share ── */
.share-wrap {
display: flex; align-items: center; gap: 12px; margin-bottom: 20px;
}
.share-wrap .label { font-size: .78rem; color: var(--text-light); font-weight: 600; text-transform: uppercase; letter-spacing: 1px; }
.share-btn {
width: 38px; height: 38px; border-radius: 50%; border: 1px solid #e0ddd8;
background: #fff; color: var(--text-medium); display: flex;
align-items: center; justify-content: center; text-decoration: none;
transition: all .2s; font-size: .9rem;
}
.share-btn:hover { border-color: var(--gold); color: var(--gold-dark); transform: translateY(-2px); }
/* ── Tabs ── */
.tabs-section { margin-top: 48px; background: #fff; border-radius: 20px; box-shadow: 0 2px 20px rgba(0,0,0,.04); overflow: hidden; }
.tabs-header {
display: flex; border-bottom: 1px solid #f0ede8; padding: 0 24px;
}
.tab-btn {
padding: 18px 24px; border: none; background: none; font-weight: 600;
font-size: .9rem; color: var(--text-light); position: relative;
cursor: pointer; transition: color .2s; display: flex; align-items: center; gap: 8px;
}
.tab-btn:hover { color: var(--gerua); }
.tab-btn.active { color: var(--maroon); }
.tab-btn.active::after {
content: ''; position: absolute; bottom: 0; left: 24px; right: 24px;
height: 3px; background: var(--gold); border-radius: 3px 3px 0 0;
}
.tab-content-wrap { padding: 32px 24px; }
.tab-pane-custom { display: none; }
.tab-pane-custom.active { display: block; }
/* ── Upcoming Badge ── */
.upcoming-badge-lg {
display: inline-flex; align-items: center; gap: 8px;
background: linear-gradient(135deg, #D4AF37 0%, #F5E27A 50%, #D4AF37 100%);
color: #3D1A00; font-weight: 800; font-size: 1rem;
padding: 8px 20px; border-radius: 50px;
box-shadow: 0 4px 20px rgba(212,175,55,0.4);
letter-spacing: 0.5px;
}
/* ── Reviews ── */
.reviews-layout { display: grid; grid-template-columns: 280px 1fr; gap: 32px; }
@media (max-width: 768px) { .reviews-layout { grid-template-columns: 1fr; } }
.rev-summary-card { text-align: center; padding: 20px; background: #fafafa; border-radius: 14px; margin-bottom: 16px; }
.rev-avg-big { font-size: 3.2rem; font-weight: 800; color: var(--maroon); line-height: 1; }
.rev-avg-stars { color: var(--gold); font-size: 1.1rem; margin: 6px 0; letter-spacing: 2px; }
.rev-avg-count { font-size: .85rem; color: var(--text-light); }
.rev-bar-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: .8rem; }
.rev-bar-label { width: 44px; text-align: right; color: var(--text-medium); font-weight: 600; flex-shrink: 0; }
.rev-bar-label i { color: var(--gold); font-size: .65rem; }
.rev-bar-track { flex: 1; height: 8px; background: #e8e5e0; border-radius: 10px; overflow: hidden; }
.rev-bar-fill { height: 100%; background: var(--gold); border-radius: 10px; transition: width .4s; }
.rev-bar-count { width: 24px; color: var(--text-light); font-weight: 600; flex-shrink: 0; text-align: right; }
.review-item { padding: 16px 0; border-bottom: 1px solid #f0ede8; }
.review-item:last-of-type { border-bottom: none; }
.review-header { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 8px; }
.review-avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--gradient-saffron); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: .95rem; flex-shrink: 0; }
.review-meta { flex: 1; }
.review-author { font-size: .9rem; display: block; }
.review-stars-sm { color: var(--gold); font-size: .75rem; letter-spacing: 1px; }
.review-date { font-size: .75rem; color: var(--text-light); flex-shrink: 0; }
.review-title { font-weight: 700; font-size: .92rem; color: var(--text-dark); margin-bottom: 4px; }
.review-comment { font-size: .88rem; color: var(--text-medium); line-height: 1.6; margin: 0; }
.user-review-highlight { background: #fffbeb; border-radius: 12px; padding: 16px; border: 1px solid rgba(212,175,55,.25); }
.star-rating-input { display: flex; flex-direction: row-reverse; justify-content: flex-end; gap: 2px; }
.star-rating-input input { display: none; }
.star-rating-input label { font-size: 1.8rem; color: #ddd; cursor: pointer; transition: color .15s; }
.star-rating-input label:hover,
.star-rating-input label:hover ~ label,
.star-rating-input input:checked ~ label { color: var(--gold); }
.review-form .form-control { border: 1.5px solid #e0ddd8; border-radius: 10px; padding: 10px 14px; font-size: .9rem; }
.review-form .form-control:focus { border-color: var(--gold); box-shadow: 0 0 0 3px rgba(212,175,55,.15); }
/* ── Related ── */
.related-section { margin-top: 48px; }
.related-section h3 {
font-family: 'Inter', sans-serif;
font-weight: 700;
color: var(--maroon); font-size: 1.3rem; margin-bottom: 20px;
}
.related-grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 16px;
}
.related-card {
background: #fff; border-radius: 14px; overflow: hidden;
box-shadow: 0 2px 12px rgba(0,0,0,.04); border: 1px solid #f0ede8;
transition: all .25s; text-decoration: none; color: inherit;
}
.related-card:hover { transform: translateY(-4px); box-shadow: 0 8px 28px rgba(0,0,0,.08); border-color: rgba(212,175,55,.25); }
.related-img { height: 200px; background: var(--cream); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.related-img img { width: 100%; height: 100%; object-fit: cover; }
.related-body { padding: 14px 16px; }
.related-body h6 { font-size: .85rem; font-weight: 700; color: var(--text-dark); margin-bottom: 2px; }
.related-body .auth { font-size: .75rem; color: var(--text-light); margin-bottom: 6px; }
.related-body .pric { font-weight: 700; color: var(--maroon-light); font-size: .9rem; }
/* ── Responsive ── */
@media (max-width: 992px) {
.fk-zoom-result { display: none !important; }
.fk-main-img { cursor: default; }
.detail-section { padding-left: 0; margin-top: 20px; }
.specs-grid { grid-template-columns: repeat(3,1fr); }
}
@media (max-width: 576px) {
.specs-grid { grid-template-columns: repeat(2,1fr); }
.highlights-bar { grid-template-columns: repeat(2,1fr); }
.related-grid { grid-template-columns: repeat(2,1fr); }
.tabs-header { overflow-x: auto; gap: 0; }
.tab-btn { padding: 14px 16px; font-size: .82rem; white-space: nowrap; }
}
</style>
<!-- Page Header -->
<div class="bg-dark text-white py-3" style="background: var(--gradient-divine) !important; border-bottom: 1px solid rgba(212,175,55,.2);">
<div class="container">
<nav aria-label="breadcrumb">
<ol class="breadcrumb bg-transparent p-0 m-0">
<li class="breadcrumb-item"><a href="index.php" class="text-decoration-none" style="color:var(--gerua-light)">Home</a></li>
<li class="breadcrumb-item"><a href="shop.php" class="text-decoration-none" style="color:var(--gerua-light)">Books</a></li>
<li class="breadcrumb-item"><a href="shop.php?cat=<?php echo $book['cat_slug']; ?>" class="text-decoration-none" style="color:var(--gerua-light)"><?php echo $book['cat_name']; ?></a></li>
<li class="breadcrumb-item active" aria-current="page" style="color:var(--gold)"><?php echo $book['title']; ?></li>
</ol>
</nav>
</div>
</div>
<div class="book-detail-page py-4">
<div class="container">
<div class="row g-4">
<!-- Image Gallery -->
<div class="col-lg-5">
<div class="book-gallery-wrap">
<div class="fk-gallery">
<div class="fk-main-img" id="fkMainWrap">
<img id="fkMainImg" src="<?php echo eurl($all_images[0]); ?>"
data-zoom="<?php echo eurl($all_images[0]); ?>"
alt="<?php echo $book['title']; ?>"
onerror="this.src='images/placeholder.png'">
<div class="fk-lens" id="fkLens"></div>
<div class="fk-zoom-result" id="fkZoomResult"></div>
<button class="wishlist-float" id="wishlistFloat" onclick="toggleWishlist(this)" title="Wishlist">
<i class="bi bi-heart"></i>
</button>
</div>
<?php if ($total_images > 1): ?>
<div class="fk-thumbs" id="fkThumbs">
<?php foreach($all_images as $i => $img_url): ?>
<div class="fk-thumb <?php echo $i === 0 ? 'active' : ''; ?>" data-index="<?php echo $i; ?>">
<img src="<?php echo eurl($img_url); ?>" alt="Thumbnail"
onerror="this.parentElement.style.display='none'">
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
<!-- Book Details -->
<div class="col-lg-7">
<div class="detail-section">
<span class="badge-category mb-2"><i class="bi bi-bookmark-fill"></i> <?php echo $book['cat_name']; ?></span>
<h1 class="book-title-detail"><?php echo $book['title']; ?></h1>
<?php if ($book['title_bengali']): ?>
<p class="book-title-bengali"><?php echo $book['title_bengali']; ?></p>
<?php endif; ?>
<!-- Author + Rating -->
<div class="author-row">
<div class="author-avatar-detail">
<i class="bi bi-person-fill"></i>
</div>
<div class="author-meta">
<div class="label">Author</div>
<div class="name"><?php echo $book['author']; ?></div>
</div>
<div class="vr text-secondary opacity-25"></div>
<div class="text-center" style="min-width:90px">
<div class="rating-stars" id="detailRatingStars">
<?php for ($i = 1; $i <= 5; $i++):
if ($i <= $filled): ?>
<i class="bi bi-star-fill"></i>
<?php elseif ($i == $filled + 1 && $half): ?>
<i class="bi bi-star-half"></i>
<?php else: ?>
<i class="bi bi-star"></i>
<?php endif;
endfor; ?>
</div>
<div class="rating-text"><?php echo $avg_rating; ?>/5 • <?php echo $review_count; ?> rating<?php echo $review_count !== 1 ? 's' : ''; ?></div>
</div>
</div>
<!-- Price -->
<div class="price-card-detail">
<?php if($book['is_upcoming']): ?>
<div class="text-center py-2">
<span class="upcoming-badge-lg"><i class="bi bi-stars"></i> Coming Soon</span>
<?php if(!empty($book['release_date'])): ?>
<div class="mt-2" style="color:var(--gerua);font-weight:600;font-size:0.95rem">
<i class="bi bi-calendar-event"></i> Expected Release: <?php echo date('d M Y', strtotime($book['release_date'])); ?>
</div>
<?php endif; ?>
<div class="mt-2 text-muted" style="font-size:0.85rem">Pre-orders will be available soon. Stay tuned!</div>
</div>
<?php else: ?>
<div class="price-row">
<span class="price-current">₹<?php echo $book['price']; ?></span>
<?php if ($book['original_price'] > $book['price']): ?>
<del class="price-original">₹<?php echo $book['original_price']; ?></del>
<span class="price-badge"><?php echo $book['original_price'] > 0 ? round((1 - $book['price']/$book['original_price'])*100) : 0; ?>% OFF</span>
<?php endif; ?>
</div>
<div class="price-offer-row">
<span class="offer-tag"><i class="bi bi-truck"></i> Free Delivery above ₹999</span>
<span class="offer-tag"><i class="bi bi-arrow-return-left"></i> 7-Day Returns</span>
<span class="offer-tag"><i class="bi bi-credit-card"></i> EMI Available</span>
</div>
<div class="stock-badge"><i class="bi bi-patch-check-fill"></i> In Stock & Ready to Ship</div>
<?php endif; ?>
</div>
<!-- Highlights -->
<div class="highlights-bar">
<div class="highlight-item">
<i class="bi bi-book"></i>
<span class="val"><?php echo $book['pages'] ?: '-'; ?></span>
<span class="lbl">Pages</span>
</div>
<div class="highlight-item">
<i class="bi bi-translate"></i>
<span class="val"><?php echo $book['language'] ?: '-'; ?></span>
<span class="lbl">Language</span>
</div>
<div class="highlight-item">
<i class="bi bi-file-earmark-text"></i>
<span class="val"><?php echo $book['binding'] ?: 'Paperback'; ?></span>
<span class="lbl">Binding</span>
</div>
<div class="highlight-item">
<i class="bi bi-upc-scan"></i>
<span class="val"><?php echo $book['isbn'] ?: '-'; ?></span>
<span class="lbl">ISBN</span>
</div>
</div>
<!-- Description -->
<div class="desc-wrap">
<h5><i class="bi bi-journal-text me-2 text-gold"></i>Quick Overview</h5>
<p class="mb-0"><?php echo $book['description']; ?></p>
</div>
<!-- Specs -->
<div class="specs-grid">
<div class="spec-card">
<i class="bi bi-book"></i>
<span class="lbl">Pages</span>
<span class="val"><?php echo $book['pages'] ?: '-'; ?></span>
</div>
<div class="spec-card">
<i class="bi bi-translate"></i>
<span class="lbl">Language</span>
<span class="val"><?php echo $book['language'] ?: '-'; ?></span>
</div>
<div class="spec-card">
<i class="bi bi-file-earmark-text"></i>
<span class="lbl">Format</span>
<span class="val"><?php echo $book['binding'] ?: 'Paperback'; ?></span>
</div>
</div>
<!-- Actions -->
<?php if($book['is_upcoming']): ?>
<div class="action-bar">
<button class="btn-buy-now" style="flex:1" onclick="alert('🔔 We will notify you when "<?php echo addslashes($book['title']); ?>" launches!');">
<i class="bi bi-bell-fill"></i> <span>NOTIFY ME</span>
</button>
</div>
<?php else: ?>
<div class="action-bar">
<div class="qty-group">
<button onclick="updateQty(-1)"><i class="bi bi-dash-lg"></i></button>
<input type="number" id="bookQty" value="1" min="1" readonly>
<button onclick="updateQty(1)"><i class="bi bi-plus-lg"></i></button>
</div>
<div class="btn-group">
<button class="btn-add-cart" onclick="handleAddToCart()">
<i class="bi bi-cart-plus-fill"></i> <span>ADD TO CART</span>
</button>
<button class="btn-buy-now" onclick="handleBuyNow()">
<i class="bi bi-lightning-charge-fill"></i> <span>BUY NOW</span>
</button>
</div>
</div>
<?php endif; ?>
<!-- Trust Strip -->
<div class="trust-strip">
<span class="trust-item"><i class="bi bi-shield-check"></i> Genuine Vedic Literature</span>
<span class="trust-item"><i class="bi bi-truck"></i> Shipping ₹80 | Free above ₹999</span>
<span class="trust-item"><i class="bi bi-arrow-repeat"></i> 7-Day Easy Return</span>
</div>
<!-- Share -->
<div class="share-wrap">
<span class="label">Share</span>
<a href="#" class="share-btn" title="WhatsApp"><i class="bi bi-whatsapp"></i></a>
<a href="#" class="share-btn" title="Facebook"><i class="bi bi-facebook"></i></a>
<a href="#" class="share-btn" title="Twitter"><i class="bi bi-twitter-x"></i></a>
<a href="#" class="share-btn" title="Copy Link" onclick="copyPageLink(this)"><i class="bi bi-link-45deg"></i></a>
</div>
</div>
</div>
</div>
<!-- Tabs -->
<div class="tabs-section">
<div class="tabs-header">
<button class="tab-btn active" data-tab="desc"><i class="bi bi-journal-richtext"></i> Detailed Insights</button>
<button class="tab-btn" data-tab="reviews"><i class="bi bi-chat-heart"></i> Reader Reviews (<?php echo $review_count; ?>)</button>
</div>
<div class="tab-content-wrap">
<div class="tab-pane-custom active" id="tab-desc">
<div class="description-content" style="line-height: 2; color: var(--text-dark); font-size: 1.05rem;">
<?php echo nl2br($book['long_description']); ?>
</div>
</div>
<div class="tab-pane-custom" id="tab-reviews">
<div class="reviews-layout">
<div class="reviews-summary-side">
<div class="rev-summary-card">
<div class="rev-avg-big"><?php echo $avg_rating; ?></div>
<div class="rev-avg-stars">
<?php for ($i = 1; $i <= 5; $i++):
if ($i <= $filled): ?>
<i class="bi bi-star-fill"></i>
<?php elseif ($i == $filled + 1 && $half): ?>
<i class="bi bi-star-half"></i>
<?php else: ?>
<i class="bi bi-star"></i>
<?php endif;
endfor; ?>
</div>
<div class="rev-avg-count"><?php echo $review_count; ?> rating<?php echo $review_count !== 1 ? 's' : ''; ?></div>
</div>
<?php for ($i = 5; $i >= 1; $i--):
$pct = $review_count > 0 ? round(($rating_distribution[$i] / $review_count) * 100) : 0; ?>
<div class="rev-bar-row">
<span class="rev-bar-label"><?php echo $i; ?> <i class="bi bi-star-fill"></i></span>
<div class="rev-bar-track"><div class="rev-bar-fill" style="width:<?php echo $pct; ?>%"></div></div>
<span class="rev-bar-count"><?php echo $rating_distribution[$i]; ?></span>
</div>
<?php endfor; ?>
</div>
<div class="reviews-list-side">
<?php if ($review_count > 0): ?>
<?php foreach ($reviews as $rv): ?>
<div class="review-item">
<div class="review-header">
<div class="review-avatar"><?php echo strtoupper(substr($rv['user_name'], 0, 1)); ?></div>
<div class="review-meta">
<strong class="review-author"><?php echo htmlspecialchars($rv['user_name']); ?></strong>
<div class="review-stars-sm">
<?php for ($i = 1; $i <= 5; $i++): ?>
<i class="bi bi-star<?php echo $i <= $rv['rating'] ? '-fill' : ''; ?>"></i>
<?php endfor; ?>
</div>
</div>
<span class="review-date"><?php echo date('d M Y', strtotime($rv['created_at'])); ?></span>
</div>
<?php if ($rv['title']): ?>
<h6 class="review-title"><?php echo htmlspecialchars($rv['title']); ?></h6>
<?php endif; ?>
<p class="review-comment"><?php echo htmlspecialchars($rv['comment']); ?></p>
</div>
<?php endforeach; ?>
<?php else: ?>
<div class="text-center py-5">
<i class="bi bi-chat-heart display-1 text-gold opacity-25"></i>
<h4 class="mt-3 fw-bold" style="color:var(--text-medium)">No reviews yet</h4>
<p class="text-muted">Be the first one to share your divine experience with this book.</p>
</div>
<?php endif; ?>
<hr class="my-4">
<h5 class="fw-bold mb-3" style="color:var(--maroon)">
<i class="bi bi-pencil-square me-2"></i>
<?php echo $user_review ? 'Your Review' : 'Write a Review'; ?>
</h5>
<?php if (isset($_SESSION['user_id'])): ?>
<?php if ($user_review): ?>
<div class="review-item user-review-highlight">
<div class="review-header">
<div class="review-avatar"><?php echo strtoupper(substr($_SESSION['user_name'], 0, 1)); ?></div>
<div class="review-meta">
<strong class="review-author"><?php echo htmlspecialchars($_SESSION['user_name']); ?></strong>
<div class="review-stars-sm">
<?php for ($i = 1; $i <= 5; $i++): ?>
<i class="bi bi-star<?php echo $i <= $user_review['rating'] ? '-fill' : ''; ?>"></i>
<?php endfor; ?>
</div>
</div>
<span class="review-date"><?php echo date('d M Y', strtotime($user_review['created_at'])); ?></span>
</div>
<?php if ($user_review['title']): ?>
<h6 class="review-title"><?php echo htmlspecialchars($user_review['title']); ?></h6>
<?php endif; ?>
<p class="review-comment"><?php echo htmlspecialchars($user_review['comment']); ?></p>
<span class="badge bg-success mt-1"><i class="bi bi-check-circle"></i> Your review submitted</span>
</div>
<?php else: ?>
<form id="reviewForm" class="review-form" onsubmit="return submitReview(event)">
<input type="hidden" name="book_id" value="<?php echo $id; ?>">
<div class="mb-3">
<label class="form-label fw-semibold">Your Rating <span class="text-danger">*</span></label>
<div class="star-rating-input" id="starRatingInput">
<?php for ($i = 5; $i >= 1; $i--): ?>
<input type="radio" name="rating" id="star<?php echo $i; ?>" value="<?php echo $i; ?>">
<label for="star<?php echo $i; ?>" title="<?php echo $i; ?> star<?php echo $i > 1 ? 's' : ''; ?>"><i class="bi bi-star-fill"></i></label>
<?php endfor; ?>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Review Title <span class="text-muted fw-normal">(optional)</span></label>
<input type="text" name="title" class="form-control" placeholder="Summarise your experience" maxlength="255">
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Your Review <span class="text-danger">*</span></label>
<textarea name="comment" class="form-control" rows="4" placeholder="Share your thoughts about this book..." required minlength="10"></textarea>
<div class="form-text">Minimum 10 characters.</div>
</div>
<button type="submit" class="btn btn-saffron px-5" id="reviewSubmitBtn">
<i class="bi bi-send-fill"></i> Submit Review
</button>
</form>
<div id="reviewMessage" class="mt-3"></div>
<?php endif; ?>
<?php else: ?>
<div class="text-center py-4 bg-light rounded-3">
<i class="bi bi-box-arrow-in-right fs-3 text-gold"></i>
<p class="mt-2 mb-2">Please <a href="login.php?redirect=<?php echo urlencode($_SERVER['REQUEST_URI']); ?>" class="fw-bold" style="color:var(--maroon)">login</a> to write a review.</p>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<!-- Related Books -->
<?php if (!empty($related)): ?>
<div class="related-section">
<h3><i class="bi bi-star me-2 text-gold"></i>You May Also Like</h3>
<div class="related-grid">
<?php foreach ($related as $r): ?>
<a href="book-detail.php?id=<?php echo $r['id']; ?>" class="related-card">
<div class="related-img">
<img src="<?php echo $r['image']; ?>" alt="<?php echo $r['title']; ?>" onerror="this.src='images/placeholder.png'">
</div>
<div class="related-body">
<h6><?php echo $r['title']; ?></h6>
<div class="auth"><?php echo $r['author']; ?></div>
<div class="pric">₹<?php echo $r['price']; ?>
<?php if ($r['original_price'] > $r['price']): ?>
<small class="text-muted text-decoration-line-through">₹<?php echo $r['original_price']; ?></small>
<?php endif; ?>
</div>
</div>
</a>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
</div>
<script>
var images = <?php echo json_encode(array_map('eurl', $all_images)); ?>;
var currentIdx = 0;
var mainImg = document.getElementById('fkMainImg');
var mainWrap = document.getElementById('fkMainWrap');
var lens = document.getElementById('fkLens');
var zoomResult = document.getElementById('fkZoomResult');
var thumbs = document.querySelectorAll('.fk-thumb');
// ── Thumbnail clicks ──
thumbs.forEach(function(el) {
el.addEventListener('click', function() {
var idx = parseInt(this.dataset.index);
if (idx === currentIdx) return;
currentIdx = idx;
thumbs.forEach(function(t) { t.classList.remove('active'); });
this.classList.add('active');
var src = images[idx];
mainImg.src = src;
mainImg.setAttribute('data-zoom', src);
this.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
});
});
// ── Zoom ──
function zoomEnter() {
lens.style.display = 'block';
zoomResult.style.display = 'block';
zoomResult.style.backgroundImage = 'url(' + mainImg.getAttribute('data-zoom') + ')';
}
function zoomLeave() {
lens.style.display = 'none';
zoomResult.style.display = 'none';
}
function zoomMove(e) {
var rect = mainWrap.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
var lensW = lens.offsetWidth / 2;
var lensH = lens.offsetHeight / 2;
var lx = x - lensW, ly = y - lensH;
if (lx < 0) lx = 0;
if (ly < 0) ly = 0;
if (lx > rect.width - lens.offsetWidth) lx = rect.width - lens.offsetWidth;
if (ly > rect.height - lens.offsetHeight) ly = rect.height - lens.offsetHeight;
lens.style.left = lx + 'px';
lens.style.top = ly + 'px';
var px = lx / (rect.width - lens.offsetWidth) * 100;
var py = ly / (rect.height - lens.offsetHeight) * 100;
zoomResult.style.backgroundPosition = px + '% ' + py + '%';
zoomResult.style.backgroundSize = (rect.width * 2.5) + 'px ' + (rect.height * 2.5) + 'px';
}
if (window.innerWidth > 992) {
mainWrap.addEventListener('mouseenter', zoomEnter);
mainWrap.addEventListener('mouseleave', zoomLeave);
mainWrap.addEventListener('mousemove', zoomMove);
}
// ── Wishlist ──
function toggleWishlist(btn) {
btn.classList.toggle('active');
var icon = btn.querySelector('i');
if (btn.classList.contains('active')) {
icon.className = 'bi bi-heart-fill';
} else {
icon.className = 'bi bi-heart';
}
}
// ── Qty ──
function updateQty(val) {
var input = document.getElementById('bookQty');
var nv = parseInt(input.value) + val;
if (nv < 1) nv = 1;
input.value = nv;
}
function handleAddToCart() {
var qty = parseInt(document.getElementById('bookQty').value);
triggerAddToCart(
'<?php echo $book['id']; ?>',
'<?php echo addslashes($book['title']); ?>',
'<?php echo addslashes($book['author']); ?>',
'<?php echo $book['price']; ?>',
'<?php echo $book['image']; ?>',
'<?php echo $book['cat_name']; ?>',
qty
);
}
function handleBuyNow() {
handleAddToCart();
window.location.href = 'cart.php';
}
// ── Copy Link ──
function copyPageLink(el) {
var input = document.createElement('input');
input.value = window.location.href;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
el.innerHTML = '<i class="bi bi-check-lg"></i>';
setTimeout(function() { el.innerHTML = '<i class="bi bi-link-45deg"></i>'; }, 2000);
}
// ── Tabs ──
(function() {
var btns = document.querySelectorAll('.tab-btn');
btns.forEach(function(btn) {
btn.addEventListener('click', function() {
btns.forEach(function(b) { b.classList.remove('active'); });
this.classList.add('active');
document.querySelectorAll('.tab-pane-custom').forEach(function(p) { p.classList.remove('active'); });
var target = document.getElementById('tab-' + this.dataset.tab);
if (target) target.classList.add('active');
});
});
})();
// ── Review Submission ──
function submitReview(e) {
e.preventDefault();
var form = document.getElementById('reviewForm');
var formData = new FormData(form);
var btn = document.getElementById('reviewSubmitBtn');
var msg = document.getElementById('reviewMessage');
// Validate rating
var rating = form.querySelector('input[name="rating"]:checked');
if (!rating) {
msg.innerHTML = '<div class="alert alert-danger py-2"><i class="bi bi-exclamation-circle"></i> Please select a rating.</div>';
return false;
}
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Submitting...';
fetch('submit-review.php', {
method: 'POST',
body: formData
})
.then(function(res) { return res.json(); })
.then(function(data) {
if (data.success) {
msg.innerHTML = '<div class="alert alert-success py-2"><i class="bi bi-check-circle"></i> ' + data.message + '</div>';
form.reset();
setTimeout(function() { location.reload(); }, 1500);
} else {
msg.innerHTML = '<div class="alert alert-danger py-2"><i class="bi bi-exclamation-circle"></i> ' + data.message + '</div>';
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-send-fill"></i> Submit Review';
}
})
.catch(function() {
msg.innerHTML = '<div class="alert alert-danger py-2"><i class="bi bi-exclamation-circle"></i> Something went wrong. Please try again.</div>';
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-send-fill"></i> Submit Review';
});
return false;
}
</script>
<?php include 'includes/footer.php'; ?>