Baza danych i zapis akcji przywoływania kelnera. Czekam na endpointy lub coś z KDS
This commit is contained in:
@@ -22,6 +22,108 @@ if (!hashParam) {
|
||||
}
|
||||
|
||||
let tableParam = ""; // Puste, zostanie uzupełnione przez backend
|
||||
const analyticsEndpoint = "../api/analytics.php";
|
||||
const guestActionQueueEndpoint = "../api/guest_action_queue.php";
|
||||
const analyticsSessionKey = "karczma_analytics_session_id";
|
||||
|
||||
function getOrCreateAnalyticsSessionId() {
|
||||
let existing = localStorage.getItem(analyticsSessionKey);
|
||||
if (existing) return existing;
|
||||
|
||||
let newId = "";
|
||||
if (window.crypto && crypto.randomUUID) {
|
||||
newId = crypto.randomUUID();
|
||||
} else {
|
||||
newId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
||||
}
|
||||
localStorage.setItem(analyticsSessionKey, newId);
|
||||
return newId;
|
||||
}
|
||||
|
||||
const analyticsSessionId = getOrCreateAnalyticsSessionId();
|
||||
|
||||
function detectDeviceType() {
|
||||
const ua = navigator.userAgent || "";
|
||||
if (/iPad|iPhone|iPod/.test(ua) || (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)) return "ios";
|
||||
if (/Android/i.test(ua)) return "android";
|
||||
return "other";
|
||||
}
|
||||
|
||||
function detectBrowser() {
|
||||
const ua = navigator.userAgent || "";
|
||||
if (/Edg\//.test(ua)) return "edge";
|
||||
if (/OPR\//.test(ua)) return "opera";
|
||||
if (/Chrome\//.test(ua)) return "chrome";
|
||||
if (/Safari\//.test(ua)) return "safari";
|
||||
if (/Firefox\//.test(ua)) return "firefox";
|
||||
return "other";
|
||||
}
|
||||
|
||||
function deriveZoneFromTable(tableValue) {
|
||||
const raw = String(tableValue || "").trim().toLowerCase();
|
||||
if (!raw) return null;
|
||||
|
||||
if (raw.startsWith("t") || raw.includes("taras")) return "taras";
|
||||
if (raw.startsWith("k") || raw.includes("karczma")) return "karczma";
|
||||
return null;
|
||||
}
|
||||
|
||||
function trackEvent(eventName, payload = {}) {
|
||||
const body = {
|
||||
eventName,
|
||||
sessionId: analyticsSessionId,
|
||||
tableId: tableParam || null,
|
||||
zone: deriveZoneFromTable(tableParam),
|
||||
qrHash: hashParam || null,
|
||||
deviceType: detectDeviceType(),
|
||||
browser: detectBrowser(),
|
||||
payload
|
||||
};
|
||||
|
||||
const bodyString = JSON.stringify(body);
|
||||
|
||||
try {
|
||||
if (navigator.sendBeacon) {
|
||||
const blob = new Blob([bodyString], { type: "application/json" });
|
||||
navigator.sendBeacon(analyticsEndpoint, blob);
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// fallback to fetch below
|
||||
}
|
||||
|
||||
fetch(analyticsEndpoint, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: bodyString,
|
||||
keepalive: true
|
||||
}).catch(() => {
|
||||
// best effort - ignore analytics errors
|
||||
});
|
||||
}
|
||||
|
||||
function queueGuestAction(messageType, messageText, extra = {}) {
|
||||
const body = {
|
||||
tableId: tableParam || null,
|
||||
qrHash: hashParam || null,
|
||||
messageType,
|
||||
messageText,
|
||||
extra
|
||||
};
|
||||
|
||||
fetch(guestActionQueueEndpoint, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
keepalive: true
|
||||
}).catch(() => {
|
||||
// best effort - ignore queue errors in UI
|
||||
});
|
||||
}
|
||||
|
||||
if (hashParam) {
|
||||
trackEvent("qr_scan", { source: "qr_link_open" });
|
||||
}
|
||||
|
||||
// USER PROFILE LOGIC
|
||||
const userProfileKey = "karczma_user_profile";
|
||||
@@ -537,6 +639,8 @@ function sendApiSimulated(actionName, details) {
|
||||
|
||||
window.callWaiter = function (type) {
|
||||
if (type === 'order') {
|
||||
trackEvent("waiter_call_requested", { waiterType: "order" });
|
||||
queueGuestAction("waiter_call", "Przywołanie kelnera", { waiterType: "order" });
|
||||
sendApiSimulated("CallWaiter_Order", { table: tableParam });
|
||||
showToast("Kelner wkrótce do Ciebie podejdzie!");
|
||||
}
|
||||
@@ -558,6 +662,7 @@ window.confirmCallWaiter = function () {
|
||||
};
|
||||
|
||||
window.openBillDialog = async function () {
|
||||
trackEvent("bill_dialog_opened");
|
||||
billState = { payment: '', doc: '', nip: '', company: null, selectedBillId: null };
|
||||
document.getElementById("billModal").classList.add("active");
|
||||
document.body.style.overflow = 'hidden'; // Zablokuj scroll tła
|
||||
@@ -671,6 +776,7 @@ window.switchTab = function (tabName) {
|
||||
|
||||
// 2. Nadaj .active wybranym elementom
|
||||
if (tabName === 'status') {
|
||||
trackEvent("view_status");
|
||||
const view = document.getElementById('statusView');
|
||||
view.classList.remove('hidden');
|
||||
view.classList.add('active');
|
||||
@@ -680,6 +786,7 @@ window.switchTab = function (tabName) {
|
||||
if (greetingBanner && greetingBanner.innerHTML.trim() !== '') greetingBanner.style.display = '';
|
||||
}
|
||||
else if (tabName === 'menu') {
|
||||
trackEvent("view_menu");
|
||||
const view = document.getElementById('menuView');
|
||||
view.classList.remove('hidden');
|
||||
view.classList.add('active');
|
||||
@@ -693,6 +800,11 @@ window.switchTab = function (tabName) {
|
||||
// --- MENU LOGIC ---
|
||||
window.filterMenu = function () {
|
||||
const query = document.getElementById('menuSearchInput').value.toLowerCase();
|
||||
const now = Date.now();
|
||||
if (query.length >= 2 && (!window.lastMenuSearchEventAt || now - window.lastMenuSearchEventAt > 8000)) {
|
||||
window.lastMenuSearchEventAt = now;
|
||||
trackEvent("menu_search", { queryLength: query.length });
|
||||
}
|
||||
const categories = document.querySelectorAll('.rm-category');
|
||||
|
||||
categories.forEach(category => {
|
||||
@@ -749,6 +861,12 @@ window.selectPayment = function (method) {
|
||||
window.selectDocument = function (docType) {
|
||||
billState.doc = docType;
|
||||
if (docType === 'paragon') {
|
||||
trackEvent("bill_request_sent", { docType: "paragon" });
|
||||
const queueMessage = `Prośba o rachunek | forma płatności: ${billState.payment || "nieznana"} | dokument: paragon`;
|
||||
queueGuestAction("bill_request", queueMessage, {
|
||||
payment: billState.payment || null,
|
||||
docType: "paragon"
|
||||
});
|
||||
closeBillDialog();
|
||||
sendApiSimulated("CallWaiter_Bill", { table: tableParam, billId: billState.selectedBillId, payment: billState.payment, doc: 'paragon' });
|
||||
showToast("Kelner przyniesie paragon do opłacenia!");
|
||||
@@ -931,6 +1049,14 @@ window.confirmInvoice = function () {
|
||||
billState.company.city = document.getElementById("cmpCity").value;
|
||||
|
||||
closeBillDialog();
|
||||
trackEvent("bill_request_sent", { docType: "faktura" });
|
||||
const queueMessage = `Prośba o rachunek | forma płatności: ${billState.payment || "nieznana"} | dokument: faktura | NIP: ${billState.nip || "-"} | firma: ${billState.company?.name || "-"}`;
|
||||
queueGuestAction("bill_request", queueMessage, {
|
||||
payment: billState.payment || null,
|
||||
docType: "faktura",
|
||||
nip: billState.nip || null,
|
||||
company: billState.company || null
|
||||
});
|
||||
sendApiSimulated("CallWaiter_Bill", {
|
||||
table: tableParam,
|
||||
billId: billState.selectedBillId,
|
||||
@@ -964,6 +1090,7 @@ function haversineDistance(lat1, lon1, lat2, lon2) {
|
||||
function startApp() {
|
||||
document.getElementById("geoScreen").classList.add("hidden");
|
||||
document.getElementById("loadingScreen").classList.remove("hidden");
|
||||
trackEvent("session_start", { flow: "start_app" });
|
||||
|
||||
initUserProfile();
|
||||
fetchOrders();
|
||||
@@ -1010,6 +1137,7 @@ function shouldBypassGeolocationHost() {
|
||||
window.initGeolocation = function () {
|
||||
if (shouldBypassGeolocationHost()) {
|
||||
console.warn("Bypassing geolocation for trusted host.");
|
||||
trackEvent("geo_bypass_host", { host: window.location.hostname, reason: "trusted_host" });
|
||||
startApp();
|
||||
return;
|
||||
}
|
||||
@@ -1022,6 +1150,7 @@ window.initGeolocation = function () {
|
||||
const bypassHosts = ['localhost', '127.0.0.1', '192.168.20.84'];
|
||||
if (window.location.protocol === 'http:' && bypassHosts.includes(window.location.hostname)) {
|
||||
console.warn("Bypassing geolocation on local HTTP environment.");
|
||||
trackEvent("geo_bypass_host", { host: window.location.hostname, reason: "local_http" });
|
||||
startApp();
|
||||
return;
|
||||
}
|
||||
@@ -1048,6 +1177,7 @@ window.initGeolocation = function () {
|
||||
}
|
||||
|
||||
geoMsg.innerHTML = "Sprawdzamy Twoją lokalizację...";
|
||||
trackEvent("geo_check_started");
|
||||
if (geoActionBtn) {
|
||||
geoActionBtn.disabled = true;
|
||||
geoActionBtn.textContent = "Sprawdzanie...";
|
||||
@@ -1064,9 +1194,11 @@ window.initGeolocation = function () {
|
||||
console.log(`[GEO] Lat: ${position.coords.latitude}, Lng: ${position.coords.longitude}, Dist: ${dist}m, Accuracy: ${accuracy}m`);
|
||||
|
||||
if (dist <= MAX_DISTANCE_METERS) {
|
||||
trackEvent("geo_check_passed", { distanceMeters: Math.round(dist), accuracyMeters: Math.round(accuracy) });
|
||||
startApp();
|
||||
// setTimeout(() => showToast(`Lokalizacja zweryfikowana (Dystans: ${Math.round(dist)}m, Dokładność: ${Math.round(accuracy)}m)`), 2000);
|
||||
} else {
|
||||
trackEvent("geo_check_failed", { reason: "outside_restaurant", distanceMeters: Math.round(dist), accuracyMeters: Math.round(accuracy) });
|
||||
if (geoActionBtn) {
|
||||
geoActionBtn.disabled = false;
|
||||
geoActionBtn.textContent = "Spróbuj ponownie";
|
||||
@@ -1077,6 +1209,7 @@ window.initGeolocation = function () {
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
trackEvent("geo_check_failed", { reason: "browser_error", code: error.code || null, message: String(error.message || "") });
|
||||
if (geoActionBtn) {
|
||||
geoActionBtn.disabled = false;
|
||||
geoActionBtn.textContent = "Spróbuj ponownie";
|
||||
|
||||
Reference in New Issue
Block a user