<!DOCTYPE html>
<html lang="{{ app.session.get('_locale') ?? 'en' }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ produit.productName }} โ Julico</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/julico-home.css">
<style>
body{background:var(--gray-50);min-height:100vh}
.prod-nav{background:var(--white);border-bottom:1px solid var(--gray-200);padding:0 24px;height:68px;display:flex;align-items:center;justify-content:space-between;box-shadow:var(--shadow-sm);position:sticky;top:0;z-index:100}
.prod-body{max-width:1280px;margin:0 auto;padding:28px 24px}
.breadcrumb{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--gray-400);margin-bottom:24px;flex-wrap:wrap}
.breadcrumb a{color:var(--gray-400);text-decoration:none;transition:color .2s}
.breadcrumb a:hover{color:var(--brand)}
.breadcrumb span{color:var(--gray-800);font-weight:600}
.prod-layout{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start}
.main-image{background:var(--white);border:1.5px solid var(--gray-100);border-radius:var(--rlg);overflow:hidden;aspect-ratio:1;display:flex;align-items:center;justify-content:center;margin-bottom:12px;box-shadow:var(--shadow-sm);position:relative}
.main-image img{width:80%;height:80%;object-fit:contain;transition:transform .3s}
.main-image:hover img{transform:scale(1.05)}
.main-image .no-img{font-size:80px;opacity:0.2}
.thumb-grid{display:flex;gap:10px;overflow-x:auto;scrollbar-width:none}
.thumb-grid::-webkit-scrollbar{display:none}
.thumb{width:72px;height:72px;background:var(--white);border:2px solid var(--gray-200);border-radius:var(--rsm);overflow:hidden;cursor:pointer;flex-shrink:0;display:flex;align-items:center;justify-content:center;transition:border-color .2s}
.thumb:hover,.thumb.active{border-color:var(--brand)}
.thumb img{width:100%;height:100%;object-fit:contain;pointer-events:none}
.prod-info{}
.prod-badges{display:flex;gap:8px;margin-bottom:14px;flex-wrap:wrap}
.prod-badge{font-size:11px;font-weight:700;padding:4px 10px;border-radius:100px}
.badge-promo{background:#fef3c7;color:#b45309}
.badge-new{background:#dcfce7;color:#166534}
.badge-b2b{background:var(--brand-light);color:var(--brand-dark)}
.badge-oos{background:#fee2e2;color:#991b1b}
.prod-name{font-size:28px;font-weight:800;color:var(--gray-900);letter-spacing:-0.02em;line-height:1.2;margin-bottom:8px}
.prod-cat{font-size:13px;font-weight:600;color:var(--brand);margin-bottom:16px}
.prod-desc{font-size:14px;color:var(--gray-500);line-height:1.7;margin-bottom:20px}
.prod-price-box{background:var(--brand-light);border:1.5px solid var(--brand-mid);border-radius:var(--r);padding:20px;margin-bottom:20px}
.prod-price{font-size:36px;font-weight:800;color:var(--brand);letter-spacing:-0.02em;line-height:1}
.prod-price sup{font-size:18px;font-weight:700;vertical-align:super}
.prod-old-price{font-size:16px;color:var(--gray-400);text-decoration:line-through;font-weight:500;margin-top:4px}
.prod-tax{font-size:12px;color:var(--gray-400);margin-top:6px}
.prod-stock{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;margin-bottom:20px}
.stock-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.stock-in{background:#22c55e}
.stock-out{background:#ef4444}
.variants-section{margin-bottom:20px}
.variants-label{font-size:13px;font-weight:700;color:var(--gray-700);margin-bottom:10px}
.color-options{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.color-opt{width:34px;height:34px;border-radius:50%;border:3px solid transparent;cursor:pointer;transition:all .2s;outline:2px solid var(--gray-200)}
.color-opt:hover,.color-opt.active{outline-color:var(--brand);outline-offset:2px}
.size-options{display:flex;gap:8px;flex-wrap:wrap}
.size-opt{padding:8px 16px;border:1.5px solid var(--gray-200);border-radius:var(--rsm);font-size:13px;font-weight:600;color:var(--gray-700);cursor:pointer;transition:all .2s;background:var(--white);font-family:var(--font)}
.size-opt:hover,.size-opt.active{border-color:var(--brand);color:var(--brand);background:var(--brand-light)}
.prod-actions{display:flex;gap:12px;align-items:center;margin-bottom:20px}
.qty-wrap{display:flex;align-items:center;gap:0;border:1.5px solid var(--gray-200);border-radius:var(--rsm);overflow:hidden;background:var(--white)}
.qty-btn-large{width:44px;height:50px;background:var(--white);border:none;color:var(--gray-700);font-size:20px;font-weight:600;cursor:pointer;transition:background .2s;font-family:var(--font)}
.qty-btn-large:hover{background:var(--gray-100)}
.qty-input{width:60px;height:50px;border:none;border-left:1px solid var(--gray-200);border-right:1px solid var(--gray-200);text-align:center;font-family:var(--font);font-size:16px;font-weight:700;color:var(--gray-900);outline:none}
.btn-add-cart{flex:1;height:50px;background:var(--brand);color:white;border:none;border-radius:var(--rsm);font-family:var(--font);font-size:15px;font-weight:700;cursor:pointer;transition:background .2s;display:flex;align-items:center;justify-content:center;gap:8px;touch-action:manipulation}
.btn-add-cart:hover{background:var(--brand-dark)}
.btn-checkout-now{flex:1;height:50px;background:var(--gray-900);color:white;border:none;border-radius:var(--rsm);font-family:var(--font);font-size:15px;font-weight:700;cursor:pointer;transition:background .2s;display:flex;align-items:center;justify-content:center;gap:8px;touch-action:manipulation}
.btn-checkout-now:hover{background:var(--gray-700)}
.info-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:20px}
.info-card{background:var(--white);border:1.5px solid var(--gray-100);border-radius:var(--r);padding:14px;text-align:center;box-shadow:var(--shadow-sm)}
.info-card-icon{font-size:22px;margin-bottom:6px}
.info-card-title{font-size:12px;font-weight:700;color:var(--gray-700)}
.info-card-sub{font-size:11px;color:var(--gray-400);margin-top:2px}
.cart-toast{position:fixed;bottom:30px;left:50%;transform:translateX(-50%) translateY(20px);background:var(--gray-900);color:white;padding:14px 24px;border-radius:100px;font-size:13px;font-weight:600;display:flex;align-items:center;gap:12px;box-shadow:0 8px 32px rgba(0,0,0,0.25);z-index:400;opacity:0;pointer-events:none;transition:all .3s;white-space:nowrap}
.cart-toast.show{opacity:1;transform:translateX(-50%) translateY(0);pointer-events:auto}
.cart-toast a{color:var(--brand);font-weight:700;text-decoration:none;margin-left:4px}
@media(max-width:900px){.prod-layout{grid-template-columns:1fr}.prod-actions{flex-wrap:wrap}}
</style>
</head>
<body>
<nav class="prod-nav">
<a href="{{ path('app_home') }}">
<img src="/images/julico-logo.png" alt="Julico" style="height:48px;object-fit:contain">
</a>
<div style="display:flex;align-items:center;gap:12px">
<a href="{{ path('app_panier') }}" style="display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;color:var(--gray-600);text-decoration:none;padding:8px 14px;border:1.5px solid var(--gray-200);border-radius:var(--rsm)">
๐ Cart
</a>
{% if app.user %}
<a href="{{ path('app_orders') }}" style="font-size:13px;font-weight:600;color:var(--gray-600);text-decoration:none;padding:8px 14px;border:1.5px solid var(--gray-200);border-radius:var(--rsm)">๐ฆ Orders</a>
<a href="{{ path('app_profile') }}" style="font-size:13px;font-weight:600;color:var(--brand);text-decoration:none">{{ app.user.pseudo }}</a>
{% else %}
<a href="/login" style="font-size:13px;font-weight:600;color:var(--brand);text-decoration:none">Sign In</a>
{% endif %}
</div>
</nav>
<div class="prod-body">
<div class="breadcrumb">
<a href="{{ path('app_home') }}">Home</a> โบ
{% if produit.category is defined and produit.category %}
<a href="{{ path('app_home') }}">{{ produit.category.nom }}</a> โบ
{% endif %}
<span>{{ produit.productName }}</span>
</div>
<div class="prod-layout">
<!-- IMAGES -->
<div class="prod-images">
<div class="main-image">
{% if produit.images|length > 0 %}
{# โโ Main image โ src set by JS on thumb click โโ #}
<img id="main-img"
src="{{ asset('assets/uploads/products/' ~ produit.images|first.fileName) }}"
alt="{{ produit.productName }}"
onerror="this.onerror=null;this.parentNode.innerHTML='<div class=no-img>๐ฆ</div>'">
{% else %}
<div class="no-img">๐ฆ</div>
{% endif %}
</div>
{% if produit.images|length > 1 %}
<div class="thumb-grid" id="thumb-grid">
{% for image in produit.images %}
<div class="thumb {% if loop.first %}active{% endif %}"
data-src="{{ asset('assets/uploads/products/' ~ image.fileName) }}"
data-fallback="/assets/uploads/products/{{ image.fileName }}">
<img src="{{ asset('assets/uploads/products/' ~ image.fileName) }}"
alt="{{ loop.index }}"
onerror="this.onerror=null;this.src='/assets/uploads/products/{{ image.fileName }}'">
</div>
{% endfor %}
</div>
{% endif %}
</div>
<!-- INFO -->
<div class="prod-info">
<div class="prod-badges">
{% if produit.promo %}<span class="prod-badge badge-promo">๐ฅ On Promo</span>{% endif %}
{% if produit.qtt > 0 %}
<span class="prod-badge badge-new">โ
In Stock</span>
{% else %}
<span class="prod-badge badge-oos">โ Out of Stock</span>
{% endif %}
{% if produit.magasin is defined and produit.magasin %}
<span class="prod-badge badge-b2b">{{ produit.magasin.nom }}</span>
{% endif %}
</div>
<div class="prod-name">{{ produit.productName }}</div>
<div class="prod-cat">
{% if produit.category is defined and produit.category %}{{ produit.category.nom }}{% endif %}
{% if produit.magasin is defined and produit.magasin %} ยท {{ produit.magasin.nom }}{% endif %}
</div>
<div class="prod-desc">{{ produit.description }}</div>
<div class="prod-price-box">
{% if produit.promo and produit.salePrice and produit.salePrice > 0 and produit.salePrice < produit.prix %}
<div class="prod-price"><sup>$</sup>{{ produit.salePrice|number_format(2) }}</div>
<div class="prod-old-price">${{ produit.prix|number_format(2) }}</div>
{% else %}
<div class="prod-price"><sup>$</sup>{{ produit.prix|number_format(2) }}</div>
{% endif %}
<div class="prod-tax">Price includes applicable taxes</div>
</div>
<div class="prod-stock">
<span class="stock-dot {{ produit.qtt > 0 ? 'stock-in' : 'stock-out' }}"></span>
{% if produit.qtt > 0 %}
<span style="color:#16a34a">In Stock ({{ produit.qtt }} available)</span>
{% else %}
<span style="color:#dc2626">Out of Stock</span>
{% endif %}
</div>
{% if groupedVariantscolor|length > 0 %}
<div class="variants-section">
<div class="variants-label">Color:</div>
<div class="color-options">
{% for color, variants in groupedVariantscolor %}
<div class="color-opt" data-color="{{ color }}"
style="background-color:{{ color }}" title="{{ color }}"></div>
{% endfor %}
</div>
</div>
{% endif %}
{% if groupedVariantssize|length > 0 %}
<div class="variants-section">
<div class="variants-label">Size:</div>
<div class="size-options">
{% for size, variants in groupedVariantssize %}
<button type="button" class="size-opt" data-size="{{ size }}">{{ size }}</button>
{% endfor %}
</div>
</div>
{% endif %}
{% if produit.qtt > 0 %}
<form method="post" id="cart-form">
<input type="hidden" id="chosenColor" name="chosenColor">
<input type="hidden" id="chosenSize" name="chosenSize">
<input type="hidden" name="productid" value="{{ produit.id }}">
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<div class="prod-actions">
<div class="qty-wrap">
<button type="button" class="qty-btn-large" id="qty-minus">โ</button>
<input type="number" class="qty-input" id="qttprdid" name="qttprdid"
min="1" max="{{ produit.qtt }}" value="1">
<button type="button" class="qty-btn-large" id="qty-plus">+</button>
</div>
<button type="button" class="btn-add-cart" id="btn-add-cart"
data-add-url="{{ path('panier_add', {'id': produit.id, 'idVariante': 'notdefined', 'option': 'continue'}) }}">
๐ Add to Cart
</button>
<button type="submit" class="btn-checkout-now"
formaction="{{ path('panier_add', {'id': produit.id, 'idVariante': 'notdefined', 'option': 'done'}) }}">
โก Buy Now
</button>
</div>
</form>
{% else %}
<div style="background:#fee2e2;border:1.5px solid #fecaca;border-radius:var(--rsm);padding:16px;text-align:center;color:#dc2626;font-weight:600;margin-bottom:20px">
โ This product is currently out of stock
</div>
{% endif %}
<div class="info-cards">
<div class="info-card"><div class="info-card-icon">๐</div><div class="info-card-title">Fast Delivery</div><div class="info-card-sub">Next-day dispatch</div></div>
<div class="info-card"><div class="info-card-icon">๐</div><div class="info-card-title">Secure Payment</div><div class="info-card-sub">100% protected</div></div>
<div class="info-card"><div class="info-card-icon">โฉ๏ธ</div><div class="info-card-title">Easy Returns</div><div class="info-card-sub">Hassle-free policy</div></div>
</div>
</div>
</div>
</div>
<div class="cart-toast" id="cart-toast">
<span>โ Added to cart!</span>
<a href="{{ path('app_panier') }}">View Cart โ</a>
</div>
<script>
// โโ IMAGE GALLERY โ data-src approach, no inline onclick โโ
document.addEventListener('DOMContentLoaded', function() {
// Thumbnail click โ switch main image
var thumbGrid = document.getElementById('thumb-grid');
if (thumbGrid) {
thumbGrid.addEventListener('click', function(e) {
var thumb = e.target.closest('.thumb');
if (!thumb) return;
var src = thumb.dataset.src;
var fallback = thumb.dataset.fallback;
var mainImg = document.getElementById('main-img');
if (mainImg && src) {
mainImg.src = src;
mainImg.onerror = function() {
this.onerror = null;
this.src = fallback;
};
}
// Update active state
document.querySelectorAll('.thumb').forEach(function(t) {
t.classList.remove('active');
});
thumb.classList.add('active');
});
}
// โโ Qty buttons โโ
var qtyInput = document.getElementById('qttprdid');
var qtyMinus = document.getElementById('qty-minus');
var qtyPlus = document.getElementById('qty-plus');
if (qtyMinus && qtyInput) {
qtyMinus.addEventListener('click', function() {
var val = parseInt(qtyInput.value) - 1;
qtyInput.value = Math.max(1, val);
});
}
if (qtyPlus && qtyInput) {
qtyPlus.addEventListener('click', function() {
var val = parseInt(qtyInput.value) + 1;
var max = parseInt(qtyInput.max) || 999;
qtyInput.value = Math.min(max, val);
});
}
// โโ Color selection โโ
document.querySelectorAll('.color-opt').forEach(function(el) {
el.addEventListener('click', function() {
document.querySelectorAll('.color-opt').forEach(function(c) { c.classList.remove('active'); });
el.classList.add('active');
var chosenColor = document.getElementById('chosenColor');
if (chosenColor) chosenColor.value = el.dataset.color;
});
});
// โโ Size selection โโ
document.querySelectorAll('.size-opt').forEach(function(el) {
el.addEventListener('click', function() {
document.querySelectorAll('.size-opt').forEach(function(s) { s.classList.remove('active'); });
el.classList.add('active');
var chosenSize = document.getElementById('chosenSize');
if (chosenSize) chosenSize.value = el.dataset.size;
});
});
// โโ AJAX Add to Cart โโ
var addBtn = document.getElementById('btn-add-cart');
if (addBtn) {
addBtn.addEventListener('click', function() {
var form = document.getElementById('cart-form');
var addUrl = addBtn.dataset.addUrl;
var origTxt = addBtn.innerHTML;
addBtn.innerHTML = 'โฆ';
addBtn.style.opacity = '0.7';
addBtn.disabled = true;
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.open('POST', addUrl);
xhr.withCredentials = true;
xhr.onload = function() {
// Show toast
var toast = document.getElementById('cart-toast');
if (toast) {
toast.classList.add('show');
setTimeout(function() { toast.classList.remove('show'); }, 4000);
}
addBtn.innerHTML = 'โ Added!';
addBtn.style.background = '#16a34a';
addBtn.style.opacity = '1';
setTimeout(function() {
addBtn.innerHTML = origTxt;
addBtn.style.background = '';
addBtn.disabled = false;
}, 1500);
};
xhr.onerror = function() {
// Fallback: normal submit
addBtn.innerHTML = origTxt;
addBtn.style.opacity = '1';
addBtn.disabled = false;
form.action = addUrl;
form.submit();
};
xhr.send(formData);
});
}
});
</script>
</body>
</html>