<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: "Artystyczne wisz\u0105ce kolczyki z elementami niemetalowymi", langCode: 'pl'});</script><script>console.log('[T_PL] ⏭️ Język PL lub pusty - zwracam bez tłumaczenia');</script>Artystyczne wiszące kolczyki z elementami niemetalowymi

Artystyczne wiszące kolczyki z elementami niemetalowymi

Zaloguj się, aby zobaczyć ceny

Odśwież swój strój tymi fantazyjnymi, wiszącymi kolczykami. Wykonane z dbałością o szczegóły, charakteryzują się zabawną kaskadą elementów niemetalowych, dodających im artystycznego charakteru. Żółte złoto dopełnia całość, tworząc wyrazisty dodatek idealny dla osób ceniących oryginalne dodatki.

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 (_) {} })(); });