1import { getCart, subscribe } from './cart.js'; 2import { getCustomerToken, getCustomerUser } from './customer-auth.js'; 3import { apiFetch } from './site-api.js'; 4 5const CART_SESSION_KEY = 'planeta_cart_session_id'; 6const SYNC_DEBOUNCE_MS = 1600; 7 8let syncTimer = null; 9let lastFingerprint = ''; 10let initialized = false; 11 12function createCartSessionId() { 13 try { 14 if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { 15 return `c-${crypto.randomUUID()}`; 16 } 17 } catch { 18 // ignore 19 } 20 return `c-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`; 21} 22 23export function getCartSessionId() { 24 try { 25 let id = String(localStorage.getItem(CART_SESSION_KEY) || '').trim(); 26 if (id.length >= 8) return id; 27 id = createCartSessionId(); 28 localStorage.setItem(CART_SESSION_KEY, id); 29 return id; 30 } catch { 31 return createCartSessionId(); 32 } 33} 34 35export function rotateCartSessionId() { 36 const id = createCartSessionId(); 37 try { 38 localStorage.setItem(CART_SESSION_KEY, id); 39 } catch { 40 // ignore 41 } 42 lastFingerprint = ''; 43 return id; 44} 45 46function readCheckoutContact() { 47 const user = getCustomerUser() || {}; 48 const emailEl = document.getElementById('email'); 49 const nameEl = document.getElementById('name'); 50 const phoneEl = document.getElementById('phone'); 51 const email = String(emailEl?.value || user.email || '').trim(); 52 const name = String(nameEl?.value || user.name || '').trim(); 53 const phone = String(phoneEl?.value || user.phone || '').trim(); 54 return { email, name, phone }; 55} 56 57function cartFingerprint(items, contact) { 58 const slim = (items || []).map((item) => ({ 59 id: item.id, 60 size: item.size || null, 61 q: item.quantity, 62 p: item.price, 63 })); 64 return JSON.stringify({ slim, email: contact.email, name: contact.name, phone: contact.phone }); 65} 66 67function slimItems(items) { 68 return (items || []).map((item) => ({ 69 id: item.id || '', 70 name: item.name || '', 71 size: item.size || null, 72 quantity: item.quantity || 1, 73 price: item.price || 0, 74 extras: (item.extras || []).map((extra) => ({ 75 id: extra.id || '', 76 name: extra.name || '', 77 })), 78 })); 79} 80 81export async function syncCartToServer(items = getCart()) { 82 const contact = readCheckoutContact(); 83 const fingerprint = cartFingerprint(items, contact); 84 if (fingerprint === lastFingerprint) return; 85 lastFingerprint = fingerprint; 86 87 const typeEl = document.querySelector('.cart-tab.is-active[data-type]'); 88 const orderType = typeEl?.dataset?.type || 'delivery'; 89 90 try { 91 await apiFetch('carts.php', { 92 method: 'POST', 93 skipAuth: true, 94 body: { 95 action: 'upsert', 96 cartId: getCartSessionId(), 97 items: slimItems(items), 98 email: contact.email, 99 name: contact.name, 100 phone: contact.phone, 101 orderType, 102 channel: 'site', 103 customerToken: getCustomerToken() || undefined, 104 }, 105 }); 106 } catch (err) { 107 lastFingerprint = ''; 108 console.warn('Nie udaÅo siÄ zapisaÄ koszyka:', err); 109 } 110} 111 112function scheduleCartSync(items) { 113 if (syncTimer) clearTimeout(syncTimer); 114 syncTimer = setTimeout(() => { 115 syncTimer = null; 116 void syncCartToServer(items); 117 }, SYNC_DEBOUNCE_MS); 118} 119 120export async function markCartCompleted(orderId = '', email = '') { 121 const cartId = getCartSessionId(); 122 try { 123 await apiFetch('carts.php', { 124 method: 'POST', 125 skipAuth: true, 126 body: { 127 action: 'complete', 128 cartId, 129 orderId, 130 email, 131 customerToken: getCustomerToken() || undefined, 132 }, 133 }); 134 } catch (err) { 135 console.warn('Nie udaÅo siÄ oznaczyÄ koszyka jako zrealizowany:', err); 136 } 137 rotateCartSessionId(); 138} 139 140export function initCartSync() { 141 if (initialized) return; 142 initialized = true; 143 subscribe((items) => scheduleCartSync(items)); 144 ['email', 'name', 'phone'].forEach((id) => { 145 const el = document.getElementById(id); 146 if (!el) return; 147 el.addEventListener('blur', () =>
147 scheduleCartSync(getCart())); 148 el.addEventListener('change', () => scheduleCartSync(getCart())); 149 }); 150 window.addEventListener('planeta:customer-auth', () => scheduleCartSync(getCart())); 151 if (getCart().length) { 152 scheduleCartSync(getCart()); 153 } 154}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.