<script>console.log('[T] Wywołanie:', {text: Torba na zakupy" class="icon"> Koszyk <script>console.log('[T] Wywołanie:', {text: Ulubione" class="icon"> Ulubione <script>console.log('[T] Wywołanie:', {text: Zamówienia" class="icon"> Moje zamówienia <script>console.log('[T] Wywołanie:', {text: Upraszanie" class="icon"> Moje prośby <script>console.log('[T] Wywołanie:', {text: Pogawędzić" class="icon"> Pomoc w czacie

Koszyk

Twój koszyk jest pusty.

'; setBadge(0); if (totalValueEl) totalValueEl.textContent = fmtPrice(0); return; } setBadge(items.length); cartContent.innerHTML = items.map(it => `
${it.size ? `
Rozmiar: ${it.size}
` : ''}
Usuń
${fmtPrice(it.price)}
`).join(''); const total = items.reduce((sum, it) => sum + (it.price * it.quantity), 0); if (totalValueEl) totalValueEl.textContent = fmtPrice(total); } // >>> ZMIANA: przy braku zalogowania pokazujemy pusty koszyk, bez redirectu async function loadCart(open = true){ try{ // przekaż aktualny język do API, aby T_PL wiedziało jaki język zwrócić const lang = (location.pathname.split('/')[1] || 'pl').slice(0,2); const data = await fetchJSON('/api/cart_list.php?lang=' + encodeURIComponent(lang)); if (data && data.ok) { renderCart(data.items); } else if (data && data.error === 'AUTH_REQUIRED') { // niezalogowany → pokaż pusty koszyk renderCart([]); } else { // inne błędy → pokaż choć pusty, nie krzycz renderCart([]); console.warn('cart_list fallback:', data); } }catch(e){ console.error(e); renderCart([]); // fallback } finally { if (open) openCart(); } } async function addToCart(productId, quantity=1){ try{ const data = await fetchJSON('/api/cart_add.php', { method:'POST', headers:{'Content-Type':'application/json','Accept':'application/json'}, body: JSON.stringify({product_id: productId, quantity}) }); if(data.ok){ setBadge(data.count); await loadCart(true); // === NOWE: efekt highlight na produkcie === const productEl = document.querySelector(`[data-product-id="${productId}"]`); if (productEl) { productEl.classList.add('product-highlight'); setTimeout(() => productEl.classList.remove('product-highlight'), 2000); } } else if(data.error==='AUTH_REQUIRED'){ window.location.href = '/pl/login_choose.php'; } }catch(e){ console.error('addToCart failed', e); } } async function removeFromCart(productId, size = null){ try{ const body = { product_id: productId }; if (size) body.size = size; const data = await fetchJSON('/api/cart_remove.php', { method:'POST', headers:{'Content-Type':'application/json','Accept':'application/json'}, body: JSON.stringify(body) }); if(data.ok){ setBadge(data.count); await loadCart(false); } else if(data.error==='AUTH_REQUIRED'){ renderCart([]); } }catch(e){ console.error('removeFromCart failed', e); } } let isEditingQty = false; async function getStockMax(pid){ try{ const r = await fetchJSON(`/api/stock_quantity.php?product_id=${encodeURIComponent(pid)}`); return r && r.ok ? (r.stock ?? r.quantity ?? 9999) : 9999; }catch{ return 9999; } } async function setCartQty(pid, newQty, size = null){ const removeBody = { product_id: pid }; if (size) removeBody.size = size; await fetchJSON('/api/cart_remove.php', { method:'POST', headers:{'Content-Type':'application/json','Accept':'application/json'}, body: JSON.stringify(removeBody) }); if (newQty > 0){ const addBody = { product_id: pid, quantity: newQty }; if (size) addBody.size = size; await fetchJSON('/api/cart_add.php', { method:'POST', headers:{'Content-Type':'application/json','Accept':'application/json'}, body: JSON.stringify(addBody) }); } } async function applyQtyFromInput(inputEl){ const pid = parseInt(inputEl.dataset.pid,10); const size = inputEl.dataset.size || null; if(!pid) return; isEditingQty = true; try{ const stockMax = await getStockMax(pid); let val = parseInt(inputEl.value,10); if (Number.isNaN(val)) val = 1; val = Math.max(1, Math.min(stockMax, val)); const itemEl = inputEl.closest('.cart-item'); const current = parseInt(itemEl?.dataset.qty || '1',10); if (val !== current){ await setCartQty(pid, val, size); if (itemEl) itemEl.dataset.qty = String(val); await loadCart(false); } inputEl.value = val; }catch(e){ console.error(e); }finally{ setTimeout(()=>{ isEditingQty = false; }, 300); } } // === Triggery if (cartBtn) { cartBtn.addEventListener('click', function(e){ e.preventDefault(); // Zawsze otwórz panel; zawartość wg zalogowania loadCart(true); }); } closeBtn.addEventListener('click', closeCart); cartOverlay.addEventListener('click', closeCart); // Delegacja: add-to-cart document.body.addEventListener('click', function(e) { const btn = e.target.closest('.add-to-cart,[data-add-to-cart]'); if (!btn) return; // Zawsze wysuń koszyk loadCart(true); // Nie dodawaj jeszcze raz, jeśli to #add-to-cart z product.php if (btn.id === 'add-to-cart') return; e.preventDefault(); const rawId = btn.dataset.productId || btn.getAttribute('data-product-id') || btn.dataset.id; const pid = parseInt(rawId, 10); if (!pid) return; addToCart(pid, 1); }); // Delegacja: remove cartContent.addEventListener('click', function(e){ const rem = e.target.closest('.cart-remove[data-remove]'); if(!rem) return; const pid = parseInt(rem.dataset.remove,10); const size = rem.dataset.size || null; if(pid){ removeFromCart(pid, size); } }); // Delegacja dla ± i inputa cartContent.addEventListener('click', async (e)=>{ const incBtn = e.target.closest('[data-qty-inc]'); const decBtn = e.target.closest('[data-qty-dec]'); if (!incBtn && !decBtn) return; const btn = incBtn || decBtn; const pid = parseInt(btn.dataset.pid,10); const size = btn.dataset.size || null; if(!pid) return; // Znajdź input z tym samym pid i size const inputs = cartContent.querySelectorAll(`.cart-qty-input[data-pid="${pid}"]`); let input = null; for (const inp of inputs) { if ((inp.dataset.size || null) === size) { input = inp; break; } } if(!input) return; const step = incBtn ? +1 : -1; let next = parseInt(input.value,10); if(Number.isNaN(next)) next = 1; next += step; const stockMax = await getStockMax(pid); next = Math.max(1, Math.min(stockMax, next)); input.value = next; await applyQtyFromInput(input); }); cartContent.addEventListener('keydown', (e)=>{ const inp = e.target.closest('.cart-qty-input'); if(!inp) return; if (e.key === 'Enter'){ e.preventDefault(); inp.blur(); } }); cartContent.addEventListener('blur', (e)=>{ const inp = e.target.closest('.cart-qty-input'); if(!inp) return; applyQtyFromInput(inp); }, true); // Checkout → checkout.php (link już ma href) if (checkoutBtn && checkoutBtn.tagName === 'BUTTON') { checkoutBtn.addEventListener('click', function(e){ e.preventDefault(); window.location.href = '/checkout.php'; }); } // Badge na starcie (bez redirectu dla niezalogowanych) (async ()=>{ try{ const d = await fetchJSON('/api/cart_count.php'); if (d && d.ok) setBadge(d.count); else if (d && d.error === 'AUTH_REQUIRED') setBadge(0); }catch(_){ /* cicho */ } })(); // Auto-odświeżanie zawartości, jeśli panel otwarty i nie edytujemy ilości setInterval(() => { if (cartSidebar.classList.contains('open') && !isEditingQty) { loadCart(false); } }, 700); }); <script>console.log('[T_PL] Wywołanie:', {text: "Klasyczny sygnet z kaboszonem onyksowym", langCode: 'pl'});</script><script>console.log('[T_PL] ⏭️ Język PL lub pusty - zwracam bez tłumaczenia');</script>Klasyczny sygnet z kaboszonem onyksowym

Klasyczny sygnet z kaboszonem onyksowym

Zaloguj się, aby zobaczyć ceny

Ten elegancki sygnet zdobi czarny onyks o okrągłym szlifie kaboszonowym, oferując klasyczny, a zarazem nowoczesny wygląd. Jego minimalistyczny design podkreśla wyjątkowy urok nieprzezroczystego kamienia szlachetnego, idealnie nadając każdej stylizacji nutę subtelnej elegancji.

NASZE PRODUKTY
Nasza biżuteria ze stali nierdzewnej jest trwała i stylowa. Odporna na matowienie, korozję i zużycie, idealnie nadaje się do codziennego użytku, nie rezygnując z elegancji.
WYSYŁKA
Wysyłka na cały świat
Proszę wybrać rozmiar'); return; } } let qty = parseInt(input.value, 10) || 1; if (available > 0) qty = Math.min(Math.max(qty, 1), available); addToCart(pid, qty, selectedSize); }); } (async () => { try { const resp = await fetch('/api/cart_count.php', { headers: { 'Accept': 'application/json' } }); const json = await resp.json(); if (json.ok) setBadge(json.count); } catch (_) {} })(); });