Compare commits

..

4 Commits

Author SHA1 Message Date
BartekGit 67854b20a4 Wycofanie pytania o lokalizacjąna apple. 2026-05-27 17:00:19 +02:00
BartekGit ef8f1472fa Komunikat o testach 2026-05-27 15:19:58 +02:00
BartekGit f4fb540652 Poprawka generatora QR i ukrycie imienia 2026-05-27 15:06:53 +02:00
BartekGit d54c93623f Ukrycie opcji wzywania kelnera 2026-05-27 14:46:19 +02:00
8 changed files with 1167 additions and 116 deletions
+52
View File
@@ -0,0 +1,52 @@
const fs = require('fs');
const html = fs.readFileSync('menu.txt', 'utf8');
const items = [];
const regexCategory = /<div class="rm-category">([\s\S]*?)<\/div>\s*<\/div>/g;
const regexTitle = /class="restaurant-menu-category">([^<]+)<\/a>/;
const regexPosition = /<div class="rmc-position" data-position="([^"]*)" data-category-id="([^"]*)" data-tag="([^"]*)">([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/g; // wait, the structure is a bit complex for simple regex.
// Let's use basic string splitting.
const cats = html.split('<div class="rm-category">');
cats.shift(); // remove first empty
const result = [];
cats.forEach(catHtml => {
const titleMatch = catHtml.match(/class="restaurant-menu-category">([^<]+)<\/a>/);
const categoryName = titleMatch ? titleMatch[1].trim() : '';
const itemsMatches = catHtml.split('<div class="rmc-position"');
itemsMatches.shift();
const categoryItems = [];
itemsMatches.forEach(itemHtml => {
const idMatch = itemHtml.match(/data-position="([^"]*)"/);
const catIdMatch = itemHtml.match(/data-category-id="([^"]*)"/);
const tagMatch = itemHtml.match(/data-tag="([^"]*)"/);
const imgMatch = itemHtml.match(/<img[^>]+src="([^"]+)"/);
const titleTextMatch = itemHtml.match(/<h4>([^<]+)/);
const descMatch = itemHtml.match(/<span>([^<]*)<\/span>/);
const priceMatch = itemHtml.match(/<div class="rmc-other">\s*<span>([^<]+)<\/span>/);
categoryItems.push({
position: idMatch ? idMatch[1] : '',
categoryId: catIdMatch ? catIdMatch[1] : '',
tag: tagMatch ? tagMatch[1] : '',
image: imgMatch ? imgMatch[1] : '',
title: titleTextMatch ? titleTextMatch[1].trim() : '',
description: descMatch ? descMatch[1].trim() : '',
price: priceMatch ? priceMatch[1].trim() : ''
});
});
result.push({
categoryName,
items: categoryItems
});
});
fs.writeFileSync('public/menu.json', JSON.stringify(result, null, 2));
console.log('Saved public/menu.json');
+46 -81
View File
@@ -28,9 +28,11 @@
<div class="geo-text"> <div class="geo-text">
<h2>Prywatność i Lokalizacja</h2> <h2>Prywatność i Lokalizacja</h2>
<div class="geo-msg" id="geoMsg"> <div class="geo-msg" id="geoMsg">
Aby zapewnić bezpieczeństwo Twojego zamówienia, musimy upewnić się, że znajdujesz się na terenie restauracji.<br><br>Prosimy o udzielenie zgody na dostęp do lokalizacji w przeglądarce. Aby zapewnić bezpieczeństwo Twojego zamówienia, musimy upewnić się, że znajdujesz się na terenie
restauracji.<br><br>Prosimy o udzielenie zgody na dostęp do lokalizacji w przeglądarce.
</div> </div>
<button class="btn btn-primary" style="margin-top: 24px; max-width: 250px; margin-left: auto; margin-right: auto;" onclick="initGeolocation()">Udziel zgody / Sprawdź</button> <button class="btn btn-primary" style="margin-top: 24px; max-width: 250px; margin-left: auto; margin-right: auto;"
onclick="initGeolocation()">Udziel zgody / Sprawdź</button>
</div> </div>
</div> </div>
@@ -39,10 +41,15 @@
<h1 class="logo-text">Karczma Biesiada</h1> <h1 class="logo-text">Karczma Biesiada</h1>
<div id="tableLabel" class="table-badge">Wybierz stolik</div> <div id="tableLabel" class="table-badge">Wybierz stolik</div>
</header> </header>
<div id="greetingBanner" <div style="background: rgba(226, 176, 126, 0.1); border: 1px solid rgba(226, 176, 126, 0.3); border-radius: 12px; padding: 12px; margin-bottom: 24px; text-align: center; font-size: 13px; color: var(--text-muted); line-height: 1.5;">
style="display:none; text-align:center; padding: 10px; font-weight:600; color:var(--primary); font-family:'Playfair Display', serif; font-size:18px;"> <span style="color: var(--primary); font-weight: 600; display: block; margin-bottom: 4px;">Wdrażamy nową aplikację! 🚀</span>
Testujemy właśnie nowe funkcje. Niebawem z tego miejsca będziesz mógł wezwać obsługę lub poprosić o rachunek.
</div> </div>
<!-- <div id="greetingBanner"
style="display:none; text-align:center; padding: 10px; font-weight:600; color:var(--primary); font-family:'Playfair Display', serif; font-size:18px;">
</div> -->
<main id="mainContent"> <main id="mainContent">
<div id="statusView" class="view-section active"> <div id="statusView" class="view-section active">
@@ -98,82 +105,23 @@
<div class="restaurant-menu-container"> <div class="restaurant-menu-container">
<nav class="menu-categories-nav"> <nav class="menu-categories-nav">
<ul> <ul>
<li><a href="#" class="active" data-category-badge="0" onclick="showCategory(0)">Wszystko</a></li> <li><a href="#" class="active" data-category-badge="0" onclick="showCategory(0)">Wszystko</a></li>
<li><a href="#" onclick="showCategory(1)" data-category-badge="1">Przystawki</a></li> <li><a href="#" onclick="showCategory(1)" data-category-badge="1">Przystawki</a></li>
<li><a href="#" onclick="showCategory(2)" data-category-badge="2">Zupy</a></li> <li><a href="#" onclick="showCategory(2)" data-category-badge="2">Zupy</a></li>
<li><a href="#" onclick="showCategory(3)" data-category-badge="3">Dania główne</a></li> <li><a href="#" onclick="showCategory(3)" data-category-badge="3">Dania główne</a></li>
<li><a href="#" onclick="showCategory(4)" data-category-badge="4">Dania swojskie</a></li> <li><a href="#" onclick="showCategory(4)" data-category-badge="4">Dania swojskie</a></li>
<li><a href="#" onclick="showCategory(5)" data-category-badge="5">Ryby</a></li> <li><a href="#" onclick="showCategory(5)" data-category-badge="5">Ryby</a></li>
<li><a href="#" onclick="showCategory(7)" data-category-badge="7">Sałatki</a></li> <li><a href="#" onclick="showCategory(7)" data-category-badge="7">Sałatki</a></li>
<li><a href="#" onclick="showCategory(6)" data-category-badge="6">Makarony</a></li> <li><a href="#" onclick="showCategory(6)" data-category-badge="6">Makarony</a></li>
<li><a href="#" onclick="showCategory(9)" data-category-badge="9">Dla dzieci</a></li> <li><a href="#" onclick="showCategory(9)" data-category-badge="9">Dla dzieci</a></li>
<li><a href="#" onclick="showCategory(8)" data-category-badge="8">Dodatki</a></li> <li><a href="#" onclick="showCategory(8)" data-category-badge="8">Dodatki</a></li>
<li><a href="#" onclick="showCategory(10)" data-category-badge="10">Desery</a></li> <li><a href="#" onclick="showCategory(10)" data-category-badge="10">Desery</a></li>
<li><a href="#" onclick="showCategory(11)" data-category-badge="11">Napoje</a></li> <li><a href="#" onclick="showCategory(11)" data-category-badge="11">Napoje</a></li>
</ul> </ul>
</nav> </nav>
<div class="restaurant-menu-scroll"> <div class="restaurant-menu-scroll" id="menuContainer">
<div class="rm-category" data-cat-id="1"> <!-- Dynamiczne menu załaduje się tutaj -->
<div class="restaurant-menu-category">Na dobry początek</div>
<div class="rmc-positions">
<div class="rmc-position" data-position="331" data-category-id="1">
<img class="rmc-image" src="https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/losos-na-placku.webp" alt="" loading="lazy">
<div class="rmc-title">
<h4>Wędzony łosoś na chrupkim placku ziemniaczanym<span>ze śmietaną i sosem a'la duńskim</span></h4>
</div>
<div class="rmc-other"><span>31,00</span></div>
</div>
<div class="rmc-position" data-position="11" data-category-id="1">
<img class="rmc-image" src="https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/smalczyk.webp" alt="" loading="lazy">
<div class="rmc-title">
<h4>Skiśnięte ogórki i smolec swojej roboty z pieczywem<span></span></h4>
</div>
<div class="rmc-other"><span>28,00</span></div>
</div>
<div class="rmc-position" data-position="12" data-category-id="1">
<img class="rmc-image" src="https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/przystawki-Tatar-siekany.webp" alt="" loading="lazy">
<div class="rmc-title">
<h4>Tatar siekany z wołowiny z piklami i pieczywem<span></span></h4>
</div>
<div class="rmc-other"><span>62,00</span></div>
</div>
</div>
</div>
<div class="rm-category" data-cat-id="2">
<div class="restaurant-menu-category">Polywki</div>
<div class="rmc-positions">
<div class="rmc-position" data-position="18" data-category-id="2">
<img class="rmc-image" src="https://www.karczmabiesiada.eu/cache/images/files/wielkanocne-2020/400_320_crop/Karczma-biesiada-stalowa-wola-dania-na-wielkanoc.webp" alt="" loading="lazy">
<div class="rmc-title">
<h4>Żurek na wędzonce z jajkiem w chlebie<span></span></h4>
</div>
<div class="rmc-other"><span>31,00</span></div>
</div>
<div class="rmc-position" data-position="22" data-category-id="2">
<img class="rmc-image" src="https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/rosol-z-makaronem.webp" alt="" loading="lazy">
<div class="rmc-title">
<h4>Rosół wiejski z trzech rodzajów mięs z makaronem<span></span></h4>
</div>
<div class="rmc-other"><span>19,00</span></div>
</div>
</div>
</div>
<div class="rm-category" data-cat-id="3">
<div class="restaurant-menu-category">Co przez gospodarza lubiane</div>
<div class="rmc-positions">
<div class="rmc-position" data-position="363" data-category-id="3">
<img class="rmc-image" src="https://www.karczmabiesiada.eu/cache/images/files/aktualnosci/nowe-smaki-lato-2024/400_320_crop/pyszne-jedzenie-karczma-biesiada-6.webp" alt="" loading="lazy">
<div class="rmc-title">
<h4>Schab po zbóju z ogórkiem kiszonym podany z białym sosem i ziemniakami opiekanymi<span></span></h4>
</div>
<div class="rmc-other"><span>53,00</span></div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> <!-- Koniec menuView --> </div> <!-- Koniec menuView -->
@@ -198,10 +146,10 @@
<span class="nav-icon">📖</span> <span class="nav-icon">📖</span>
<span class="nav-label">Menu</span> <span class="nav-label">Menu</span>
</div> </div>
<div class="nav-item action-call" onclick="openWaiterDialog()"> <!-- <div class="nav-item action-call" onclick="openWaiterDialog()">
<span class="nav-icon">🛎️</span> <span class="nav-icon">🛎️</span>
<span class="nav-label">Kelner</span> <span class="nav-label">Kelner</span>
</div> </div> -->
<div class="nav-item action-bill" onclick="openBillDialog()"> <div class="nav-item action-bill" onclick="openBillDialog()">
<span class="nav-icon">💳</span> <span class="nav-icon">💳</span>
<span class="nav-label">Rachunek</span> <span class="nav-label">Rachunek</span>
@@ -226,7 +174,7 @@
</div> </div>
</div> </div>
<!-- NAME DIALOG --> <!-- NAME DIALOG (Tymczasowo wyłączone)
<div class="modal-overlay" id="nameModal"> <div class="modal-overlay" id="nameModal">
<div class="modal-content" style="text-align: center;"> <div class="modal-content" style="text-align: center;">
<div style="font-size: 48px; margin-bottom: 15px;">👋</div> <div style="font-size: 48px; margin-bottom: 15px;">👋</div>
@@ -245,6 +193,23 @@
</div> </div>
</div> </div>
</div> </div>
-->
<!-- ITEM MODAL -->
<div class="modal-overlay" id="itemModal">
<div class="modal-content" style="padding: 0; overflow: hidden; max-width: 380px;">
<div style="position: relative;">
<img id="itemModalImage" src="" style="width: 100%; height: 240px; object-fit: cover; display: block;" alt="">
<button class="close-btn" onclick="closeItemModal()" style="position: absolute; top: 10px; right: 15px; color: #fff; text-shadow: 0 2px 4px rgba(0,0,0,0.8); font-size: 32px; z-index: 10; background: rgba(0,0,0,0.3); width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; line-height: 1;">&times;</button>
</div>
<div style="padding: 24px; text-align: left;">
<h3 id="itemModalTitle" style="margin-top: 0; color: var(--text-main); font-family: 'Playfair Display', serif; font-size: 24px; margin-bottom: 8px;"></h3>
<div id="itemModalPrice" style="color: var(--primary); font-weight: 700; font-size: 20px; margin-bottom: 16px;"></div>
<p id="itemModalDesc" style="color: var(--text-muted); font-size: 15px; line-height: 1.6; margin-bottom: 24px;"></p>
<button class="btn btn-secondary" onclick="closeItemModal()" style="width: 100%;">Zamknij</button>
</div>
</div>
</div>
<!-- BILL DIALOG --> <!-- BILL DIALOG -->
<div class="modal-overlay" id="billModal"> <div class="modal-overlay" id="billModal">
@@ -280,7 +245,7 @@
<div style="display:flex; gap:12px;"> <div style="display:flex; gap:12px;">
<button class="btn btn-secondary" style="flex:1;" onclick="goBackToBillList()" <button class="btn btn-secondary" style="flex:1;" onclick="goBackToBillList()"
id="btnBackToBills">Wróć</button> id="btnBackToBills">Wróć</button>
<button class="btn btn-primary" style="flex:2;" onclick="goToStep('stepPayment')">Poproś rachunek</button> <!-- <button class="btn btn-primary" style="flex:2;" onclick="goToStep('stepPayment')">Poproś rachunek</button> -->
</div> </div>
</div> </div>
+2
View File
@@ -557,11 +557,13 @@ header {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
pointer-events: none;
} }
.toast.active { .toast.active {
transform: translateX(-50%) translateY(0); transform: translateX(-50%) translateY(0);
opacity: 1; opacity: 1;
pointer-events: auto;
} }
/* --- KITCHEN ANIMATION --- */ /* --- KITCHEN ANIMATION --- */
+160 -33
View File
@@ -28,6 +28,7 @@ const userProfileKey = "karczma_user_profile";
const USER_PROFILE_EXPIRE_MS = 180 * 24 * 60 * 60 * 1000; // ~6 months const USER_PROFILE_EXPIRE_MS = 180 * 24 * 60 * 60 * 1000; // ~6 months
function initUserProfile() { function initUserProfile() {
return; // Funkcja tymczasowo wyłączona
try { try {
const raw = localStorage.getItem(userProfileKey); const raw = localStorage.getItem(userProfileKey);
let profile = null; let profile = null;
@@ -146,7 +147,7 @@ const msgInterval = setInterval(() => {
// Initial State // Initial State
if (tableParam) { if (tableParam) {
tableLabel.textContent = `Stolik ${tableParam}`; tableLabel.textContent = tableParam.toUpperCase().startsWith("STOLIK") ? tableParam : `Stolik ${tableParam}`;
} }
function hideLoader() { function hideLoader() {
@@ -460,7 +461,7 @@ async function fetchOrders() {
if (result.status === 'success') { if (result.status === 'success') {
if (result.tableName && result.tableName !== '') { if (result.tableName && result.tableName !== '') {
tableLabel.textContent = `Stolik ${result.tableName}`; tableLabel.textContent = result.tableName.toUpperCase().startsWith("STOLIK") ? result.tableName : `Stolik ${result.tableName}`;
tableParam = result.tableName; // Aktualizacja do właściwej nazwy na poczet innych zapytań tableParam = result.tableName; // Aktualizacja do właściwej nazwy na poczet innych zapytań
} }
@@ -758,7 +759,7 @@ window.selectDocument = function (docType) {
} }
}; };
window.fetchGUS = function () { window.fetchGUS = async function () {
const nip = document.getElementById("nipInput").value.replace(/[\s-]/g, ''); const nip = document.getElementById("nipInput").value.replace(/[\s-]/g, '');
if (nip.length < 10) { if (nip.length < 10) {
alert("Wprowadź poprawny numer NIP."); alert("Wprowadź poprawny numer NIP.");
@@ -768,34 +769,136 @@ window.fetchGUS = function () {
btn.textContent = "Szukam..."; btn.textContent = "Szukam...";
btn.disabled = true; btn.disabled = true;
// Symulacja pobrania z GUS try {
setTimeout(() => { const apiKey = "d8bdc252-e0f1-4863-97a1-826faddbc49c";
const response = await fetch(`https://api.magico.pro/v1/gus/${nip}?api_key=${apiKey}`);
const result = await response.json();
if (result.status && result.data) {
const data = result.data;
let fullStreet = data.street || '';
if (data.propertyNumber) fullStreet += ' ' + data.propertyNumber;
if (data.apartmentNumber) fullStreet += '/' + data.apartmentNumber;
billState.nip = nip;
billState.company = {
name: data.name,
street: fullStreet.trim(),
zip: data.zipCode,
city: data.city,
nip: data.nip
};
document.getElementById("cmpName").value = billState.company.name;
document.getElementById("cmpStreet").value = billState.company.street;
document.getElementById("cmpZip").value = billState.company.zip;
document.getElementById("cmpCity").value = billState.company.city;
document.getElementById("cmpNip").value = "NIP: " + billState.company.nip;
// reset do readonly
document.getElementById("cmpName").readOnly = true;
document.getElementById("cmpStreet").readOnly = true;
document.getElementById("cmpZip").readOnly = true;
document.getElementById("cmpCity").readOnly = true;
document.getElementById("btnEditCompany").textContent = "Popraw ręcznie";
goToStep("stepVerify");
} else {
alert("Nie udało się pobrać danych z GUS dla podanego NIP-u.");
}
} catch (error) {
console.error("Błąd pobierania danych z GUS:", error);
alert("Błąd połączenia z API GUS.");
} finally {
btn.textContent = "Pobierz z GUS"; btn.textContent = "Pobierz z GUS";
btn.disabled = false; btn.disabled = false;
billState.nip = nip; }
billState.company = { };
name: "Przykładowa Firma Sp. z o.o.",
street: "ul. Gastronomiczna 12/4",
zip: "00-120",
city: "Warszawa",
nip: nip
};
document.getElementById("cmpName").value = billState.company.name; // --- DYNAMIC MENU LOADING ---
document.getElementById("cmpStreet").value = billState.company.street; async function loadMenu() {
document.getElementById("cmpZip").value = billState.company.zip; try {
document.getElementById("cmpCity").value = billState.company.city; const response = await fetch('menu.json');
document.getElementById("cmpNip").value = "NIP: " + billState.company.nip; if (!response.ok) throw new Error('Nie udało się załadować menu');
const menuData = await response.json();
window.menuDataRaw = menuData;
const container = document.getElementById('menuContainer');
if (!container) return;
// reset do readonly container.innerHTML = '';
document.getElementById("cmpName").readOnly = true;
document.getElementById("cmpStreet").readOnly = true;
document.getElementById("cmpZip").readOnly = true;
document.getElementById("cmpCity").readOnly = true;
document.getElementById("btnEditCompany").textContent = "Popraw ręcznie";
goToStep("stepVerify"); menuData.forEach(category => {
}, 1200); const catId = category.items.length > 0 ? category.items[0].categoryId : '';
const catDiv = document.createElement('div');
catDiv.className = 'rm-category';
catDiv.setAttribute('data-cat-id', catId);
let html = `<div class="restaurant-menu-category">${category.categoryName}</div>
<div class="rmc-positions">`;
category.items.forEach(item => {
html += `
<div class="rmc-position" data-position="${item.position}" data-category-id="${item.categoryId}" onclick="openItemModal('${item.categoryId}', '${item.position}')" style="cursor: pointer;">
<img class="rmc-image" src="${item.image}" alt="" loading="lazy">
<div class="rmc-title">
<h4>${item.title}<span>${item.description}</span></h4>
</div>
<div class="rmc-other"><span>${item.price}</span></div>
</div>
`;
});
html += `</div>`;
catDiv.innerHTML = html;
container.appendChild(catDiv);
});
} catch (err) {
console.error('Błąd ładowania menu:', err);
const container = document.getElementById('menuContainer');
if (container) {
container.innerHTML = '<p style="text-align:center; padding: 20px; color: var(--text-muted);">Nie udało się załadować menu.</p>';
}
}
}
// Inicjalizacja ładowania menu
loadMenu();
window.openItemModal = function(categoryId, position) {
if (!window.menuDataRaw) return;
let foundItem = null;
for (const cat of window.menuDataRaw) {
for (const item of cat.items) {
if (item.categoryId == categoryId && item.position == position) {
foundItem = item;
break;
}
}
if (foundItem) break;
}
if (foundItem) {
document.getElementById('itemModalImage').src = foundItem.image;
document.getElementById('itemModalTitle').textContent = foundItem.title;
document.getElementById('itemModalDesc').textContent = foundItem.description;
document.getElementById('itemModalPrice').textContent = foundItem.price;
const modal = document.getElementById('itemModal');
if (modal) {
modal.classList.add('active');
document.body.style.overflow = 'hidden';
}
}
};
window.closeItemModal = function() {
const modal = document.getElementById('itemModal');
if (modal) {
modal.classList.remove('active');
document.body.style.overflow = '';
}
}; };
window.editCompanyData = function () { window.editCompanyData = function () {
@@ -877,6 +980,15 @@ function startApp() {
} }
window.initGeolocation = function () { window.initGeolocation = function () {
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
if (isIOS) {
// Tymczasowo pomijamy weryfikację GPS tylko na urządzeniach Apple
// (wymagają bezwzględnie poprawnego certyfikatu HTTPS, inaczej blokują bez pytania)
console.warn("Bypassing geolocation on iOS.");
startApp();
return;
}
const geoScreen = document.getElementById("geoScreen"); const geoScreen = document.getElementById("geoScreen");
const loadingScreen = document.getElementById("loadingScreen"); const loadingScreen = document.getElementById("loadingScreen");
const geoMsg = document.getElementById("geoMsg"); const geoMsg = document.getElementById("geoMsg");
@@ -896,7 +1008,7 @@ window.initGeolocation = function () {
return; return;
} }
geoMsg.innerHTML = "Pobieranie lokalizacji..."; geoMsg.innerHTML = "Sprawdzamy Twoją lokalizację...";
navigator.geolocation.getCurrentPosition( navigator.geolocation.getCurrentPosition(
(position) => { (position) => {
@@ -910,7 +1022,7 @@ window.initGeolocation = function () {
if (dist <= MAX_DISTANCE_METERS) { if (dist <= MAX_DISTANCE_METERS) {
startApp(); startApp();
setTimeout(() => showToast(`Lokalizacja zweryfikowana (Dystans: ${Math.round(dist)}m, Dokładność: ${Math.round(accuracy)}m)`), 2000); // setTimeout(() => showToast(`Lokalizacja zweryfikowana (Dystans: ${Math.round(dist)}m, Dokładność: ${Math.round(accuracy)}m)`), 2000);
} else { } else {
geoMsg.innerHTML = `Wydaje się, że jesteś poza restauracją (ok. ${Math.round(dist)}m od nas).<br>Nasza aplikacja działa tylko na miejscu.<br><br> geoMsg.innerHTML = `Wydaje się, że jesteś poza restauracją (ok. ${Math.round(dist)}m od nas).<br>Nasza aplikacja działa tylko na miejscu.<br><br>
<small style="color: #888;">Debug: Twoja odległość: ${Math.round(dist)}m, Dokładność sygnału: ${Math.round(accuracy)}m</small><br><br> <small style="color: #888;">Debug: Twoja odległość: ${Math.round(dist)}m, Dokładność sygnału: ${Math.round(accuracy)}m</small><br><br>
@@ -919,11 +1031,26 @@ window.initGeolocation = function () {
}, },
(error) => { (error) => {
if (error.code === error.PERMISSION_DENIED) { if (error.code === error.PERMISSION_DENIED) {
geoMsg.innerHTML = `<b style="color: #ff6b6b;">Nie mamy Twojej zgody na lokalizację.</b><br><br> const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
Przeglądarka zapamiętała Twoją odmowę i nie możemy ponownie wyświetlić okienka z zapytaniem. Aby odblokować dostęp:<br><br>
1. Kliknij ikonkę <b>kłódki / ustawień</b> 🔒 🎚 obok adresu strony na samej górze przeglądarki.<br> let instructions = '';
2. Znajdź <b>Uprawnienia</b> (Lokalizacja) i zmień z "Zablokuj" na "Zezwalaj".<br> if (isIOS) {
3. Odśwież stronę.`; instructions = `<b>Instrukcja dla iPhone (Safari):</b><br>
1. Kliknij ikonę <b>"aA"</b> po lewej stronie paska adresu.<br>
2. Wybierz <b>"Ustawienia witryny"</b> (Website Settings).<br>
3. Zmień opcję <b>"Położenie"</b> (Location) na "Zapytaj" lub "Pozwalaj".<br>
4. Odśwież stronę.<br><br>
<i>Uwaga: Na urządzeniach Apple lokalizacja działa WYŁĄCZNIE, gdy adres strony zaczyna się od bezpiecznego <b>https://</b>. Jeżeli jesteś na http://, system zablokuje to automatycznie.</i>`;
} else {
instructions = `<b>Instrukcja dla Android / Chrome:</b><br>
1. Kliknij ikonkę <b>kłódki / ustawień</b> 🔒 obok adresu strony na górze przeglądarki.<br>
2. Znajdź <b>Uprawnienia</b> (Lokalizacja) i zmień z "Zablokuj" na "Zezwalaj".<br>
3. Odśwież stronę.`;
}
geoMsg.innerHTML = `<b style="color: #ff6b6b;">Przeglądarka zablokowała dostęp do lokalizacji.</b><br><br>
Bez tego nie możemy zweryfikować, czy jesteś w restauracji.<br><br>
${instructions}`;
} else { } else {
geoMsg.innerHTML = "Nie udało się pobrać lokalizacji. Sprawdź zasięg lub włącz GPS i spróbuj ponownie."; geoMsg.innerHTML = "Nie udało się pobrać lokalizacji. Sprawdź zasięg lub włącz GPS i spróbuj ponownie.";
} }
+828
View File
@@ -0,0 +1,828 @@
[
{
"categoryName": "Na dobry początek",
"items": [
{
"position": "331",
"categoryId": "1",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/losos-na-placku.webp",
"title": "Wędzony łosoś na chrupkim placku ziemniaczanym",
"description": "ze śmietaną i sosem a'la duńskim",
"price": "31,00"
},
{
"position": "11",
"categoryId": "1",
"tag": "kiszone,smalec",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/smalczyk.webp",
"title": "Skiśnięte ogórki i smolec swojej roboty z pieczywem",
"description": "",
"price": "28,00"
},
{
"position": "12",
"categoryId": "1",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/przystawki-Tatar-siekany.webp",
"title": "Tatar siekany z wołowiny z piklami i pieczywem",
"description": "",
"price": "62,00"
},
{
"position": "332",
"categoryId": "1",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/sledz-w-oleju.webp",
"title": "Śledź w oleju z kwaśnym dżemem morelowo-żurawinowym podany z pieczywem",
"description": "",
"price": "29,00"
},
{
"position": "260",
"categoryId": "1",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/oscypki.webp",
"title": "Grillowane serki góralskie",
"description": "z żurawiną z Podhala",
"price": "21,00"
},
{
"position": "187",
"categoryId": "1",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/rydze-z-cebula-na-grzance.webp",
"title": "Rydze z cebulą na grzance",
"description": "",
"price": "33,00"
}
]
},
{
"categoryName": "Polywki",
"items": [
{
"position": "18",
"categoryId": "2",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/wielkanocne-2020/400_320_crop/Karczma-biesiada-stalowa-wola-dania-na-wielkanoc.webp",
"title": "Żurek na wędzonce z jajkiem w chlebie",
"description": "",
"price": "31,00"
},
{
"position": "22",
"categoryId": "2",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/rosol-z-makaronem.webp",
"title": "Rosół wiejski z trzech rodzajów mięs z makaronem",
"description": "",
"price": "19,00"
},
{
"position": "25",
"categoryId": "2",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/zupy-Obszar-kompozycji-5.webp",
"title": "Barszcz czerwony ze swojskimi uszkami",
"description": "",
"price": "26,00"
},
{
"position": "374",
"categoryId": "2",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Krem z pomidorów z mozzarellą",
"description": "",
"price": "22,00"
},
{
"position": "377",
"categoryId": "2",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Kwaśnica z żeberkiem",
"description": "",
"price": "26,00"
}
]
},
{
"categoryName": "Co przez gospodarza lubiane, a i Wam polecane",
"items": [
{
"position": "363",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/aktualnosci/nowe-smaki-lato-2024/400_320_crop/pyszne-jedzenie-karczma-biesiada-6.webp",
"title": "Schab po zbóju z ogórkiem kiszonym podany z białym sosem i ziemniakami opiekanymi",
"description": "",
"price": "53,00"
},
{
"position": "324",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/miesa-Roladki-z-suszonymi-pomidorami.webp",
"title": "Kurczak z mozarellą i suszonymi pomidorami",
"description": "zawinięty boczkiem z dipem buraczkowym podany z kopytkami",
"price": "41,00"
},
{
"position": "379",
"categoryId": "",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Polędwiczki w sosie kurkowym z kopytkami i ogórkiem kiszonym",
"description": "",
"price": "54,00"
},
{
"position": "188",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/kaczka.webp",
"title": "Soczysta pierś z kaczki",
"description": "z sosem porzeczkowym z kopytkami i bukietem surówek",
"price": "69,00"
},
{
"position": "351",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/nowosci-2024/400_320_crop/1-1.webp",
"title": "Stek z polędwicy wołowej",
"description": "z puree ziemniaczanym i sosem z zielonego pieprzu",
"price": "99,00"
},
{
"position": "238",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/syte-koryto.webp",
"title": "Syte koryto (micha mięs na stół)",
"description": "W zestawie podwójna porcja: golonki, karkówki, schabu z kością, kiełbaski baraniej, szaszłyka, bekonu, ziemniaków opiekanych i kapusty zasmażanej,",
"price": "275,00"
}
]
},
{
"categoryName": "Dania mięsne",
"items": [
{
"position": "325",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/miesa-karczek-grillowany.webp",
"title": "Karczek grillowany z sosem BBQ",
"description": "z ziemniakami opiekanymi i sałatką wiosenną",
"price": "51,00"
},
{
"position": "272",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/miesa-filet-w-sosie-smietanowo_.webp",
"title": "Filet drobiowy w sosie śmietanowo-koperkowym",
"description": "z ziemniakami gotowanymi i bukietem surówek",
"price": "42,00"
},
{
"position": "273",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/filet.webp",
"title": "Filet z kurczaka panierowany",
"description": "z frytkami i surówką z białej kapusty",
"price": "39,00"
},
{
"position": "274",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/miesa-schabowy2.webp",
"title": "Kotlet schabowy panierowany",
"description": "z ziemniakami opiekanymi i kapustą zasmażaną",
"price": "40,00"
},
{
"position": "326",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/miesa-golonka1.webp",
"title": "Golonka po chłopsku z rusztu",
"description": "(z kością) z ziemniakami opiekanymi i kapustą zasmażaną",
"price": "58,00"
},
{
"position": "364",
"categoryId": "3",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/aktualnosci/nowe-smaki-lato-2024/400_320_crop/pyszne-jedzenie-karczma-biesiada-8.webp",
"title": "Żeberka pieczone podane na kapuście zasmażanej z ziemniakami opiekanymi",
"description": "",
"price": "56,00"
}
]
},
{
"categoryName": "To co w wodzie pływo",
"items": [
{
"position": "39",
"categoryId": "5",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/pstrag_nowy.webp",
"title": "Pstrąg pieczony",
"description": "z warzywami sezonowymi i ziemniakami",
"price": "57,00"
},
{
"position": "284",
"categoryId": "5",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/morszczuk.webp",
"title": "Morszczuk w panierce",
"description": "z frytkami i surówką z marchwii i ananasa",
"price": "40,00"
},
{
"position": "352",
"categoryId": "",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/sandacz-na-sosie-cytrynowym-karczma-biesiada-stalowa-wola.webp",
"title": "Sandacz podany na sosie śmietanowo-cytrynowym",
"description": "z zapiekanką ziemniaczaną i warzywami sezonowymi",
"price": "75,00"
}
]
},
{
"categoryName": "Dania swojskie",
"items": [
{
"position": "45",
"categoryId": "4",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/miesa-placek-po-wiejsku.webp",
"title": "Placek po wiejsku z gulaszem",
"description": "i surówką z białej kapusty",
"price": "40,00"
},
{
"position": "46",
"categoryId": "4",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/nalesniki-ze-szpinakiem.webp",
"title": "Naleśniki ze szpinakiem",
"description": "",
"price": "27,00"
},
{
"position": "47",
"categoryId": "4",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/pierogi-ruskie.webp",
"title": "Pierogi ruskie",
"description": "z omastą lub z patelni",
"price": "27,00"
},
{
"position": "365",
"categoryId": "4",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/aktualnosci/nowe-smaki-lato-2024/400_320_crop/pyszne-jedzenie-karczma-biesiada-3.webp",
"title": "Pierogi z oscypkiem, żurawiną i chipsami z cebulki",
"description": "",
"price": "31,00"
},
{
"position": "353",
"categoryId": "4",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/pierogi-z-miesem.webp",
"title": "Pierogi z mięsem z omastą lub z patelni",
"description": "",
"price": "29,00"
},
{
"position": "51",
"categoryId": "4",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/golabki-w-sosie-pomidorowym.webp",
"title": "Gołąbki w sosie pomidorowym",
"description": "",
"price": "31,00"
},
{
"position": "52",
"categoryId": "4",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/placki_z_wedzonka.webp",
"title": "Placki ziemniaczane ze śmietaną",
"description": "",
"price": "31,00"
}
]
},
{
"categoryName": "Makarony",
"items": [
{
"position": "373",
"categoryId": "6",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Makaron tagliatelle z kurczakiem i szpinakiem w sosie śmietanowym",
"description": "",
"price": "41,00"
},
{
"position": "355",
"categoryId": "6",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/nowosci-2024/400_320_crop/5.webp",
"title": "Makaron tagliatelle z podgrzybkami, gorgonzolą i boczkiem",
"description": "",
"price": "44,00"
}
]
},
{
"categoryName": "Sałatki",
"items": [
{
"position": "321",
"categoryId": "7",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/Salatka-z-ananasem-grillowanym-kurczakiem.webp",
"title": "Sałatka z grillowanym kurczakiem i ananasem",
"description": "Kurczak, ananas, sałata lodowa, jajo, ogórek, pomidor, sos ogrodowy, sos słodkie chili",
"price": "39,00"
},
{
"position": "320",
"categoryId": "7",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/salatka-grecka.webp",
"title": "Sałatka Grecka",
"description": "Ser favita, oliwki, cebula, ogórek, pomidor, sałata lodowa, sos ogrodowy",
"price": "37,00"
},
{
"position": "322",
"categoryId": "7",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/salatka-cezar.webp",
"title": "Sałatka Cezar",
"description": "Z kurczakiem, sosem czosnkowym, sałatą lodową, ser corregio i grzankami",
"price": "44,00"
}
]
},
{
"categoryName": "Burgery",
"items": [
{
"position": "361",
"categoryId": "",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/Burger-wolowy-karczma-biesiada-stalowa-wola.webp",
"title": "Buła z wołowiną",
"description": "",
"price": "41,00"
},
{
"position": "362",
"categoryId": "",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/nowosci-2024/400_320_crop/3.webp",
"title": "Buła z kurczakiem",
"description": "",
"price": "38,00"
}
]
},
{
"categoryName": "Dania dla dzieci",
"items": [
{
"position": "287",
"categoryId": "9",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/rosol-dla-dzieci.webp",
"title": "Rosół z makaronem",
"description": "porcja dziecięca",
"price": "14,00"
},
{
"position": "293",
"categoryId": "9",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/dzieci-nuggetsy-z-kurczaka.webp",
"title": "Nuggetsy z kurczaka",
"description": "z frytkami i surówką z marchwii i ananasa",
"price": "33,00"
},
{
"position": "294",
"categoryId": "9",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/filet-z-frytkami-dla-dzieci.webp",
"title": "Filet z kurczaka z frytkami i bukietem surówek",
"description": "porcja dziecięca",
"price": "27,00"
},
{
"position": "295",
"categoryId": "9",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/morszczuk-w-panierce-dla-dzieci.webp",
"title": "Morszczuk w panierce",
"description": "z ziemniakami i surówką z białej kapusty (porcja dziecięca)",
"price": "27,00"
},
{
"position": "296",
"categoryId": "9",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/filet-w-sosie-dla-dzieci.webp",
"title": "Filet w sosie śmietanowo-koperkowym",
"description": "z ziemniakami gotowanymi (porcja dziecięca)",
"price": "28,00"
},
{
"position": "298",
"categoryId": "9",
"tag": "deser",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/nalesniki.webp",
"title": "Naleśniki z serem",
"description": "",
"price": "24,00"
},
{
"position": "299",
"categoryId": "9",
"tag": "deser",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/dzieci-Nalesniki-z-nutella.webp",
"title": "Naleśniki z nutellą",
"description": "",
"price": "28,00"
}
]
},
{
"categoryName": "Dodatki do drugich dań",
"items": [
{
"position": "56",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/DSC088432.webp",
"title": "Ziemniaki gotowane",
"description": "",
"price": "10,00"
},
{
"position": "57",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/dodatki-ziemniaki-opiekane.webp",
"title": "Ziemniaki opiekane",
"description": "",
"price": "11,00"
},
{
"position": "58",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/frytki.webp",
"title": "Frytki",
"description": "",
"price": "12,00"
},
{
"position": "380",
"categoryId": "",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Kopytka",
"description": "",
"price": "11,00"
},
{
"position": "61",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/bukiet.webp",
"title": "Bukiet surówek",
"description": "",
"price": "12,00"
},
{
"position": "279",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/salatka-wiosenna.webp",
"title": "Sałatka wiosenna",
"description": "Pomidor, ogórek, papryka na liściu sałaty z lekkim sosem ogrodowym",
"price": "11,00"
},
{
"position": "62",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/3.webp",
"title": "Surówka z białej kapusty",
"description": "",
"price": "10,00"
},
{
"position": "67",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/buraczki.webp",
"title": "Surówka z buraczków",
"description": "",
"price": "10,00"
},
{
"position": "63",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/2.webp",
"title": "Surówka z marchwi i ananasa",
"description": "",
"price": "10,00"
},
{
"position": "65",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/kapusta-zasmazana.webp",
"title": "Kapusta zasmażana",
"description": "",
"price": "12,00"
},
{
"position": "381",
"categoryId": "",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Mizeria",
"description": "",
"price": "11,00"
},
{
"position": "66",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/ogorek-kiszony.webp",
"title": "Ogórek kiszony",
"description": "",
"price": "10,00"
},
{
"position": "68",
"categoryId": "8",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/dodatki-Chlebek-swojski-z-ziarnami.webp",
"title": "Chlebek swojski",
"description": "",
"price": "6,00"
}
]
},
{
"categoryName": "Cosik na słodko",
"items": [
{
"position": "77",
"categoryId": "10",
"tag": "deser",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/szarlotka.webp",
"title": "Szarlotka na gorąco z gałką lodów",
"description": "",
"price": "26,00"
},
{
"position": "78",
"categoryId": "10",
"tag": "deser",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/photo_2024-07-17_13-24-30.webp",
"title": "Sernik na musie truskawkowym",
"description": "",
"price": "24,00"
},
{
"position": "382",
"categoryId": "",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Fondant czekoladowy na ciepło podany na sosie wiśniowym z gałką lodów",
"description": "",
"price": "31,00"
},
{
"position": "327",
"categoryId": "10",
"tag": "deser",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/deser-3.webp",
"title": "Deser lodowy",
"description": "3 gałki, smaki do wyboru",
"price": "20,00"
},
{
"position": "292",
"categoryId": "10",
"tag": "deser",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/deser-lodowy-dla-dzieci.webp",
"title": "Mini deser lodowy",
"description": "2 gałki, smaki do wyboru",
"price": "17,00"
}
]
},
{
"categoryName": "Napitki",
"items": [
{
"position": "81",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/photo_2024-07-17_13-24-04.webp",
"title": "Espresso",
"description": "",
"price": "9,00"
},
{
"position": "82",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/kawa-czarna.webp",
"title": "Kawa czarna",
"description": "",
"price": "10,00"
},
{
"position": "83",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/kawa-biala1.webp",
"title": "Kawa biała",
"description": "",
"price": "11,00"
},
{
"position": "84",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/napoje-kawa-cappuccino.webp",
"title": "Cappuccino",
"description": "",
"price": "14,00"
},
{
"position": "86",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/latte.webp",
"title": "Latte Machiato",
"description": "",
"price": "14,00"
},
{
"position": "90",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/herbata-czarna.webp",
"title": "Herbata czarna",
"description": "",
"price": "10,00"
},
{
"position": "202",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/herbata1.webp",
"title": "Herbata Richmont",
"description": "",
"price": "14,00"
},
{
"position": "329",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/herbata-owocowa1.webp",
"title": "Herbata owocowa Richmont",
"description": "",
"price": "14,00"
},
{
"position": "330",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/menu/400_320_crop/photo_2024-07-19_08-00-49.webp",
"title": "Herbata zielona Richmont",
"description": "",
"price": "14,00"
}
]
},
{
"categoryName": "Napitki dla wysusonyk",
"items": [
{
"position": "301",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/potrawy/400_320_crop/napoje-lemoniady.webp",
"title": "Orzeźwiająca lemoniada",
"description": "",
"price": "18,00"
},
{
"position": "302",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/modzajto-light.webp",
"title": "Modżajto light",
"description": "Drink bezalkoholowy",
"price": "20,00"
},
{
"position": "304",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/400_320_crop/sok-wyciskany.webp",
"title": "Sok wyciskany ze świeżych pomarańczy lub grejpfrutów",
"description": "",
"price": "20,00"
},
{
"position": "305",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/logos/400_320_crop/logo-cocacola.webp",
"title": "Coca-Cola, Coca-Cola zero, Fanta, Sprite",
"description": "",
"price": "11,00"
},
{
"position": "309",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/logos/400_320_crop/Kinley.webp",
"title": "Tonic Kinley",
"description": "Tonic Water",
"price": "11,00"
},
{
"position": "310",
"categoryId": "11",
"tag": "woda",
"image": "https://www.karczmabiesiada.eu/cache/images/files/logos/400_320_crop/logo-kropla.webp",
"title": "Kropla Beskidu 330ml",
"description": "gazowana, niegazowana",
"price": "9,00"
},
{
"position": "359",
"categoryId": "",
"tag": "",
"image": "/themes/karczmabiesiadanew/images/icon-menu.jpg",
"title": "Dzbanek wody gazowana/niegazowana",
"description": "",
"price": "19,00"
},
{
"position": "307",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/logos/400_320_crop/logo-fuzetea.webp",
"title": "Fuzetea",
"description": "cytrynowa z trawą cytrynową, brzoskwiniowa z hibiskusem",
"price": "10,00"
},
{
"position": "308",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/logos/400_320_crop/logo-cappy.webp",
"title": "Cappy",
"description": "pomarańcza, jabłko, multiwitamina, czarna porzeczka, grejpfrut",
"price": "10,00"
},
{
"position": "312",
"categoryId": "11",
"tag": "",
"image": "https://www.karczmabiesiada.eu/cache/images/files/logos/400_320_crop/logo-burn.webp",
"title": "Burn",
"description": "napój energetyczny",
"price": "13,00"
}
]
}
]
+50 -1
View File
@@ -5,7 +5,7 @@ $tsql = "SELECT ID, Nazwa FROM dbo.NGastroStolik ORDER BY Nazwa";
$stmt = sqlsrv_query($conn, $tsql); $stmt = sqlsrv_query($conn, $tsql);
$host = $_SERVER['HTTP_HOST'] ?? 'localhost'; $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$baseUrl = "http://$host/karczma-stoliki/public/stolik2_api.html?h="; $baseUrl = "https://$host/app/public/app.html?h=";
echo "<!DOCTYPE html> echo "<!DOCTYPE html>
<html lang='pl'> <html lang='pl'>
@@ -19,7 +19,14 @@ echo "<!DOCTYPE html>
th { background: #eee; } th { background: #eee; }
a { color: #0066cc; text-decoration: none; } a { color: #0066cc; text-decoration: none; }
a:hover { text-decoration: underline; } a:hover { text-decoration: underline; }
.btn-qr { padding: 5px 10px; background: #3b82f6; color: #fff; border: none; border-radius: 4px; cursor: pointer; }
.btn-qr:hover { background: #2563eb; }
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); align-items: center; justify-content: center; }
.modal-content { background: #fff; padding: 20px; border-radius: 8px; text-align: center; max-width: 400px; width: 90%; }
.close { float: right; font-size: 24px; font-weight: bold; cursor: pointer; line-height: 20px; }
#qrcode { margin-top: 20px; display: flex; justify-content: center; }
</style> </style>
<script src='https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js'></script>
</head> </head>
<body> <body>
<h1>Linki do aplikacji (Kody QR)</h1> <h1>Linki do aplikacji (Kody QR)</h1>
@@ -29,6 +36,7 @@ echo "<!DOCTYPE html>
<th>Nazwa stolika</th> <th>Nazwa stolika</th>
<th>Hash (ID z bazy)</th> <th>Hash (ID z bazy)</th>
<th>Bezpieczny Link (KOD QR)</th> <th>Bezpieczny Link (KOD QR)</th>
<th>Akcje</th>
</tr>"; </tr>";
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
@@ -39,10 +47,51 @@ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
<td><strong>$nazwa</strong></td> <td><strong>$nazwa</strong></td>
<td style='font-size: 0.8em; color: #666;'>$id</td> <td style='font-size: 0.8em; color: #666;'>$id</td>
<td><a href='$link' target='_blank'>$link</a></td> <td><a href='$link' target='_blank'>$link</a></td>
<td><button class='btn-qr' onclick='openQR(\"$link\", \"$nazwa\")'>Pokaż QR</button></td>
</tr>"; </tr>";
} }
echo " </table> echo " </table>
<div id='qrModal' class='modal'>
<div class='modal-content'>
<span class='close' onclick='closeQR()'>&times;</span>
<h2 id='qrTitle'>Kod QR</h2>
<div id='qrcode'></div>
<p style='margin-top:20px;'><a id='qrLink' href='' target='_blank' style='color: #3b82f6;'>Otwórz link w nowym oknie</a></p>
</div>
</div>
<script>
function openQR(link, nazwa) {
document.getElementById('qrModal').style.display = 'flex';
document.getElementById('qrTitle').innerText = 'Stolik: ' + nazwa;
document.getElementById('qrLink').href = link;
var qrContainer = document.getElementById('qrcode');
qrContainer.innerHTML = ''; // Wyczyść poprzedni kod
new QRCode(qrContainer, {
text: link,
width: 250,
height: 250,
colorDark : '#000000',
colorLight : '#ffffff',
correctLevel : QRCode.CorrectLevel.H
});
}
function closeQR() {
document.getElementById('qrModal').style.display = 'none';
}
window.onclick = function(event) {
var modal = document.getElementById('qrModal');
if (event.target == modal) {
closeQR();
}
}
</script>
</body> </body>
</html>"; </html>";
+3 -1
View File
@@ -293,6 +293,7 @@
orders[orderId] = { orders[orderId] = {
number: orderId, number: orderId,
stolik: item.NazwaStolika || item.StolikID, stolik: item.NazwaStolika || item.StolikID,
stolikId: item.StolikID,
time: item.DataDodania, time: item.DataDodania,
groups: {} groups: {}
}; };
@@ -327,7 +328,8 @@
sortedOrders.forEach(order => { sortedOrders.forEach(order => {
const timeStr = new Date(order.time).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}); const timeStr = new Date(order.time).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
const stolikText = order.stolik ? `STOLIK: ${order.stolik}` : 'BRAK STOLIKA'; const stolikLink = order.stolikId ? `<a href="../app.html?h=${order.stolikId}" target="_blank" style="color: var(--accent); text-decoration: underline;">STOLIK: ${order.stolik}</a>` : `STOLIK: ${order.stolik}`;
const stolikText = order.stolik ? stolikLink : 'BRAK STOLIKA';
let itemsHtml = ''; let itemsHtml = '';
+26
View File
@@ -0,0 +1,26 @@
const fs = require('fs');
const txt = fs.readFileSync('menu.txt', 'utf8');
const json = JSON.parse(fs.readFileSync('public/menu.json', 'utf8'));
const txtItemCount = (txt.match(/<div class="rmc-position"/g) || []).length;
const txtCategoryCount = (txt.match(/<div class="rm-category">/g) || []).length - 1; // -1 because the first split in the previous script had an empty category if there was a preceding tag? Actually, let's just count `class="restaurant-menu-category"`
const txtCatNameCount = (txt.match(/class="restaurant-menu-category">/g) || []).length;
let jsonItemCount = 0;
json.forEach(cat => {
jsonItemCount += cat.items.length;
});
console.log(`Menu.txt item count: ${txtItemCount}`);
console.log(`JSON item count: ${jsonItemCount}`);
console.log(`Menu.txt category count: ${txtCatNameCount}`);
console.log(`JSON category count: ${json.length}`);
if (txtItemCount === jsonItemCount && txtCatNameCount === json.length) {
console.log("MATCH: Wszystkie pozycje i kategorie zostały prawidłowo przeniesione.");
} else {
console.log("MISMATCH: Występują braki!");
}