PageSourceSearch

https://pizzeria-planeta.pl/js/active-order-fab.js

js pizzeria-planeta.pl collected 2026-10-08 07:35:23 UTC 4,909 bytes, 181 lines download raw bytes

1import { getPublicApiUrl } from './site-api.js';
2import {
3  buildOrderTrackingUrl,
4  clearActiveOrderTracking,
5  listActiveOrderTrackings,
6  saveActiveOrderTracking
7} from './order-confirmation.js';
8import { getLocale } from './locale.js';
9import { t } from './i18n.js';
10
11const POLL_MS = 20000;
12const CHIP_ID = 'header-track-chip';
13
14let pollTimer = null;
15let inFlight = false;
16let visibilityBound = false;
17
18function shouldSkipPage() {
19  const path = (window.location.pathname || '').replace(/\\/g, '/').toLowerCase();
20  return /\/sledz\.html$/.test(path)
21    || /\/admin(?:-en)?\.html$/.test(path)
22    || /\/payment\.html$/.test(path);
23}
24
25function escapeHtml(value) {
26  return String(value ?? '')
27    .replaceAll('&', '&')
28    .replaceAll('<', '&lt;')
29    .replaceAll('>', '&gt;')
30    .replaceAll('"', '&quot;');
31}
32
33function ensureChip() {
34  let el = document.getElementById(CHIP_ID);
35  if (el) return el;
36
37  const actions = document.querySelector('.header__actions');
38  if (!actions) return null;
39
40  el = document.createElement('a');
41  el.id = CHIP_ID;
42  el.className = 'header-track';
43  el.hidden = true;
44  el.setAttribute('aria-label', t('trackFab.label'));
45  el.innerHTML = `
46    <span class="header-track__stage" aria-hidden="true">
47      <span class="header-track__road"></span>
48      <span class="header-track__dust"></span>
49      <span class="header-track__scooter">🛵</span>
50    </span>
51    <span class="header-track__text">
52      <span class="header-track__title">${escapeHtml(t('trackFab.label'))}</span>
53      <span class="header-track__hint">${escapeHtml(t('trackFab.hint'))}</span>
54    </span>
55  `;
56
57  const cartBtn = actions.querySelector('#cart-btn, .cart-btn');
58  if (cartBtn) {
59    actions.insertBefore(el, cartBtn);
60  } else {
61    actions.prepend(el);
62  }
63  return el;
64}
65
66function hideChip() {
67  const el = document.getElementById(CHIP_ID);
68  if (!el) return;
69  el.hidden = true;
70  el.removeAttribute('href');
71  document.body.classList.remove('has-header-track');
72}
73
74function showChip(href, statusLabel = '') {
75  const el = ensureChip();
76  if (!el) return;
77
78  el.href = href;
79  el.hidden = false;
80  el.setAttribute('aria-label', t('trackFab.label'));
81
82  const title = el.querySelector('.header-track__title');
83  if (title) title.textContent = t('trackFab.label');
84
85  const hint = el.querySelector('.header-track__hint');
86  if (hint) {
87    hint.textContent = statusLabel || t('trackFab.hint');
88  }
89
90  document.body.classList.add('has-header-track');
91}
92
93async function fetchTrackStatus(orderId, token) {
94  const lang = getLocale() === 'en' ? 'en' : 'pl';
95  const url = `${getPublicApiUrl('track-order.php')}?id=${encodeURIComponent(orderId)}&t=${encodeURIComponent(token)}&lang=${lang}`;
96  const res = await fetch(url, { cache: 'no-store' });
97  const data = await res.json().catch(() => ({}));
98  return { ok: res.ok, status: res.status, data };
99}
100
101function resolveHref(entry) {
102  if (entry.url) return entry.url;
103  return buildOrderTrackingUrl(entry.orderId, entry.token, {
104    lang: getLocale() === 'en' ? 'en' : ''
105  });
106}
107
108async function refreshHeaderTrack() {
109  if (shouldSkipPage() || inFlight) return;
110  inFlight = true;
111  try {
112    const entries = listActiveOrderTrackings();
113    if (!entries.length) {
114      hideChip();
115      return;
116    }
117
118    for (const entry of entries) {
119      let result;
120      try {
121        result = await fetchTrackStatus(entry.orderId, entry.token);
122      } catch {
123        continue;
124      }
125
126      if (!result.ok) {
127        if (result.status === 403 || result.status === 404) {
128          clearActiveOrderTracking(entry.orderId);
129        }
130        continue;
131      }
132
133      const data = result.data || {};
134      if (data.enabled === false) {
135        hideChip();
136        return;
137      }
138
139      const kitchenStatus = String(data.kitchenStatus || '').toLowerCase();
140      if (kitchenStatus === 'done') {
141        clearActiveOrderTracking(entry.orderId);
142        continue;
143      }
144
145      const href = resolveHref(entry);
146      saveActiveOrderTracking(entry.orderId, {
147        token: entry.token,
148        url: href,
149        deliveryLocation: entry.deliveryLocation
150      });
151
152      showChip(href, data.statusLabel || '');
153      return;
154    }
155
156    hideChip();
157  } finally {
158    inFlight = false;
159  }
160}
161
162export function initActiveOrderFab() {
163  if (shouldSkipPage()) return;
164
165  ensureChip();
166  void refreshHeaderTrack();
167
168  if (pollTimer) window.clearInterval(pollTimer);
169  pollTimer = window.setInterval(() => {
170    void refreshHeaderTrack();
171  }, POLL_MS);
172
173  if (!visibilityBound) {
174    visibilityBound = true;
175    document.addEventListener('visibilitychange', () => {
176      if (document.visibilityState === 'visible') {
177        void refreshHeaderTrack();
178      }
179    });
180  }
181}

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.