Wykrywanie i blokada po lokalizacji

This commit is contained in:
2026-05-25 23:59:00 +02:00
parent 05dfe4c3a6
commit 297ef31eca
3 changed files with 156 additions and 18 deletions

View File

@@ -62,6 +62,44 @@ body {
min-height: 20px; min-height: 20px;
} }
#geoScreen {
position: fixed;
inset: 0;
z-index: 150;
background: var(--bg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px;
text-align: center;
transition: opacity 0.5s ease, visibility 0.5s;
}
.geo-icon {
font-size: 80px;
margin-bottom: 16px;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-15px); }
}
.geo-text h2 {
font-family: 'Playfair Display', serif;
margin: 0 0 12px;
color: var(--primary);
}
.geo-msg {
color: var(--text-muted);
font-size: 15px;
line-height: 1.5;
margin-bottom: 16px;
}
/* --- MAIN LAYOUT --- */ /* --- MAIN LAYOUT --- */
.container { .container {
max-width: 500px; max-width: 500px;

View File

@@ -112,8 +112,8 @@ function showGreeting(name, firstVisitTime) {
} }
} }
// Call init // Call init is now delayed until geolocation succeeds
initUserProfile(); // initUserProfile();
// UI Elements // UI Elements
const loadingScreen = document.getElementById("loadingScreen"); const loadingScreen = document.getElementById("loadingScreen");
@@ -509,8 +509,8 @@ async function fetchOrders() {
} }
} }
fetchOrders(); // fetchOrders();
setInterval(fetchOrders, 10000); // setInterval(fetchOrders, 10000);
// --- CALL WAITER LOGIC --- // --- CALL WAITER LOGIC ---
let billState = { payment: '', doc: '', nip: '', company: null }; let billState = { payment: '', doc: '', nip: '', company: null };
@@ -839,9 +839,98 @@ window.confirmInvoice = function () {
showToast("Dziękujemy! Prośba o fakturę została wysłana."); showToast("Dziękujemy! Prośba o fakturę została wysłana.");
}; };
// --- GEOLOCATION LOGIC ---
const RESTAURANT_LAT = 50.5624963;
const RESTAURANT_LNG = 22.0608059;
const MAX_DISTANCE_METERS = 200;
function haversineDistance(lat1, lon1, lat2, lon2) {
const R = 6371e3;
const p1 = lat1 * Math.PI / 180;
const p2 = lat2 * Math.PI / 180;
const dp = (lat2 - lat1) * Math.PI / 180;
const dl = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(dp / 2) * Math.sin(dp / 2) +
Math.cos(p1) * Math.cos(p2) *
Math.sin(dl / 2) * Math.sin(dl / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function startApp() {
document.getElementById("geoScreen").classList.add("hidden");
document.getElementById("loadingScreen").classList.remove("hidden");
initUserProfile();
fetchOrders();
if (!window.ordersInterval) {
window.ordersInterval = setInterval(fetchOrders, 10000);
}
// Fallback: If no data after 25s, show empty state anyway // Fallback: If no data after 25s, show empty state anyway
setTimeout(() => { setTimeout(() => {
if (!loadingScreen.classList.contains("hidden")) { if (!document.getElementById("loadingScreen").classList.contains("hidden")) {
updateUI([]); updateUI([]);
} }
}, 25000); }, 25000);
}
window.initGeolocation = function () {
const geoScreen = document.getElementById("geoScreen");
const loadingScreen = document.getElementById("loadingScreen");
const geoMsg = document.getElementById("geoMsg");
if (window.location.protocol === 'http:' && (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1')) {
console.warn("Bypassing geolocation on local HTTP environment.");
startApp();
return;
}
loadingScreen.classList.add("hidden");
geoScreen.classList.remove("hidden");
if (!navigator.geolocation) {
geoMsg.innerHTML = "Twoja przeglądarka nie wspiera geolokalizacji. Aplikacja wymaga nowszej przeglądarki.";
return;
}
geoMsg.innerHTML = "Pobieranie lokalizacji...";
navigator.geolocation.getCurrentPosition(
(position) => {
const dist = haversineDistance(
RESTAURANT_LAT, RESTAURANT_LNG,
position.coords.latitude, position.coords.longitude
);
const accuracy = position.coords.accuracy;
console.log(`[GEO] Lat: ${position.coords.latitude}, Lng: ${position.coords.longitude}, Dist: ${dist}m, Accuracy: ${accuracy}m`);
if (dist <= MAX_DISTANCE_METERS) {
startApp();
setTimeout(() => showToast(`Lokalizacja zweryfikowana (Dystans: ${Math.round(dist)}m, Dokładność: ${Math.round(accuracy)}m)`), 2000);
} 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>
<small style="color: #888;">Debug: Twoja odległość: ${Math.round(dist)}m, Dokładność sygnału: ${Math.round(accuracy)}m</small><br><br>
Jeśli to błąd GPS lub słaby sygnał, spróbuj ponownie za chwilę.`;
}
},
(error) => {
if (error.code === error.PERMISSION_DENIED) {
geoMsg.innerHTML = `<b style="color: #ff6b6b;">Nie mamy Twojej zgody na lokalizację.</b><br><br>
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>
2. Znajdź <b>Uprawnienia</b> (Lokalizacja) i zmień z "Zablokuj" na "Zezwalaj".<br>
3. Odśwież stronę.`;
} else {
geoMsg.innerHTML = "Nie udało się pobrać lokalizacji. Sprawdź zasięg lub włącz GPS i spróbuj ponownie.";
}
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 0 }
);
};
setTimeout(() => {
initGeolocation();
}, 600);

View File

@@ -23,6 +23,17 @@
</div> </div>
</div> </div>
<div id="geoScreen" class="hidden">
<div class="geo-icon">📍</div>
<div class="geo-text">
<h2>Prywatność i Lokalizacja</h2>
<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.
</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>
</div>
</div>
<div class="container"> <div class="container">
<header id="mainHeader"> <header id="mainHeader">
<h1 class="logo-text">Karczma Biesiada</h1> <h1 class="logo-text">Karczma Biesiada</h1>