PageSourceSearch

https://pizzeria-planeta.pl/js/cart-sync.js

js pizzeria-planeta.pl collected 2026-10-08 07:35:15 UTC 4,444 bytes, 154 lines download raw bytes

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.