187 lines
7.5 KiB
HTML
187 lines
7.5 KiB
HTML
<!doctype html>
|
|
<html lang="pl">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Geocode Cache Tester</title>
|
|
<style>
|
|
:root { --gap: 12px; --radius: 12px; }
|
|
* { box-sizing: border-box; }
|
|
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; margin: 0; background: #0f172a; color: #e2e8f0; }
|
|
.wrap { max-width: 880px; margin: 40px auto; padding: 0 20px; }
|
|
h1 { font-size: 1.6rem; margin: 0 0 8px; }
|
|
p.lead { color: #94a3b8; margin: 0 0 24px; }
|
|
|
|
form { display: flex; gap: var(--gap); flex-wrap: wrap; align-items: center; background: #111827; padding: 16px; border: 1px solid #1f2937; border-radius: var(--radius); box-shadow: 0 8px 30px rgba(0,0,0,.25) inset; }
|
|
label { font-size: .95rem; color: #cbd5e1; }
|
|
input[type="text"] { flex: 1 1 420px; min-width: 260px; padding: 12px 14px; border-radius: 10px; border: 1px solid #334155; background: #0b1220; color: #e2e8f0; outline: none; }
|
|
input[type="text"]::placeholder { color: #64748b; }
|
|
button { padding: 12px 16px; border-radius: 10px; border: 1px solid #334155; background: #0b3b7a; color: #e2e8f0; cursor: pointer; }
|
|
button.secondary { background: #0b1220; }
|
|
button:disabled { opacity: .6; cursor: progress; }
|
|
|
|
.status { margin: 14px 0 0; font-size: .95rem; color: #94a3b8; min-height: 1.2em; }
|
|
|
|
.card { background: #0b1220; border: 1px solid #1f2937; border-radius: var(--radius); padding: 16px; margin-top: 18px; }
|
|
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
|
.kv { background: #0a0f1a; border: 1px solid #1f2937; border-radius: 10px; padding: 12px; }
|
|
.kv b { color: #cbd5e1; display: inline-block; min-width: 160px; }
|
|
.pill { display: inline-block; padding: 4px 10px; border-radius: 999px; border: 1px solid #334155; background: #0a0f1a; }
|
|
.ok { color: #a7f3d0; }
|
|
.warn { color: #fbbf24; }
|
|
.err { color: #fca5a5; }
|
|
|
|
details { margin-top: 10px; }
|
|
pre { background: #010409; border: 1px solid #111827; padding: 12px; border-radius: 10px; overflow: auto; }
|
|
|
|
.examples { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; }
|
|
.examples a { font-size: .9rem; text-decoration: none; color: #cbd5e1; border: 1px dashed #374151; padding: 6px 10px; border-radius: 999px; }
|
|
|
|
@media (max-width: 720px) { .grid { grid-template-columns: 1fr; } }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="wrap">
|
|
<h1>Tester geokodowania z cache (PHP + MySQL)</h1>
|
|
<p class="lead">Wpisz <b>adres</b> albo <b>"lat,lng"</b>. Front wywołuje <code>geocode-cache.php</code>, który najpierw sprawdza cache w MySQL, a dopiero potem pyta Google. W odpowiedzi zobaczysz, czy wynik pochodzi z cache.</p>
|
|
|
|
<form id="geo-form">
|
|
<label for="query">Adres lub współrzędne:</label>
|
|
<input id="query" type="text" placeholder="np. Stefana Okrzei 14, Brzeziny lub 51.7592,19.4550" required />
|
|
<button id="submit" type="submit">Geokoduj</button>
|
|
<button id="clear" type="button" class="secondary">Wyczyść</button>
|
|
</form>
|
|
|
|
<div id="status" class="status"></div>
|
|
|
|
<div class="examples">
|
|
<span class="pill">Przykłady:</span>
|
|
<a href="#" data-q="Stefana Okrzei 14, Brzeziny">Brzeziny, Okrzei 14</a>
|
|
<a href="#" data-q="Rokicińska 130, Andrespol">Andrespol, Rokicińska 130</a>
|
|
<a href="#" data-q="52.2297,21.0122">52.2297,21.0122</a>
|
|
</div>
|
|
|
|
<div id="result" class="card" hidden>
|
|
<div class="grid">
|
|
<div class="kv"><b>Źródło</b> <span id="from_cache" class="pill"></span></div>
|
|
<div class="kv"><b>Adres sformatowany</b> <span id="formatted_address"></span></div>
|
|
<div class="kv"><b>Szerokość (lat)</b> <span id="lat"></span></div>
|
|
<div class="kv"><b>Długość (lng)</b> <span id="lng"></span></div>
|
|
<div class="kv"><b>Place ID</b> <span id="place_id"></span></div>
|
|
<div class="kv"><b>Dostawca</b> <span id="provider"></span></div>
|
|
</div>
|
|
<details>
|
|
<summary>Surowa odpowiedź JSON</summary>
|
|
<pre id="raw"></pre>
|
|
</details>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// >>> DOSTOSUJ TO POLE DO SWOJEJ ŚCIEŻKI BACKENDU <<<
|
|
const API_URL = '/geocode-cache.php';
|
|
|
|
const $ = (sel) => document.querySelector(sel);
|
|
const $$ = (sel) => Array.from(document.querySelectorAll(sel));
|
|
|
|
function isLatLng(str) {
|
|
return /^-?\d+(?:\.\d+)?\s*,\s*-?\d+(?:\.\d+)?$/.test(String(str).trim());
|
|
}
|
|
|
|
async function geocode(query) {
|
|
const params = new URLSearchParams();
|
|
if (isLatLng(query)) {
|
|
const [lat, lng] = String(query).split(',').map(v => parseFloat(v.trim()));
|
|
params.set('lat', lat);
|
|
params.set('lng', lng);
|
|
} else {
|
|
params.set('q', query);
|
|
}
|
|
|
|
const res = await fetch(API_URL + '?' + params.toString(), {
|
|
method: 'GET',
|
|
headers: { 'Accept': 'application/json' },
|
|
cache: 'no-store',
|
|
});
|
|
|
|
if (!res.ok) throw new Error('HTTP ' + res.status);
|
|
|
|
const data = await res.json();
|
|
if (data && data.error) throw new Error(data.error);
|
|
if (!data || typeof data.lat !== 'number' || typeof data.lng !== 'number') {
|
|
throw new Error('Nieprawidłowa odpowiedź API');
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function setStatus(text, type = '') {
|
|
const el = $('#status');
|
|
el.textContent = text || '';
|
|
el.className = 'status ' + (type || '');
|
|
}
|
|
|
|
function renderResult(data) {
|
|
$('#result').hidden = false;
|
|
const pill = $('#from_cache');
|
|
pill.textContent = data.from_cache ? 'cache' + (data.stale ? ' (stare)' : '') : 'google';
|
|
pill.className = 'pill ' + (data.from_cache ? 'ok' : 'warn');
|
|
$('#formatted_address').textContent = data.formatted_address || '\u2013';
|
|
$('#lat').textContent = Number(data.lat).toFixed(6);
|
|
$('#lng').textContent = Number(data.lng).toFixed(6);
|
|
$('#place_id').textContent = data.place_id || '\u2013';
|
|
$('#provider').textContent = data.provider || '\u2013';
|
|
$('#raw').textContent = JSON.stringify(data, null, 2);
|
|
}
|
|
|
|
function clearResult() {
|
|
$('#result').hidden = true;
|
|
$('#raw').textContent = '';
|
|
$('#formatted_address').textContent = '';
|
|
$('#lat').textContent = '';
|
|
$('#lng').textContent = '';
|
|
$('#place_id').textContent = '';
|
|
$('#provider').textContent = '';
|
|
$('#from_cache').textContent = '';
|
|
}
|
|
|
|
$('#geo-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const btn = $('#submit');
|
|
const q = $('#query').value.trim();
|
|
if (!q) return;
|
|
|
|
clearResult();
|
|
setStatus('Szukam\u2026', '');
|
|
btn.disabled = true;
|
|
try {
|
|
const data = await geocode(q);
|
|
renderResult(data);
|
|
setStatus(data.from_cache ? 'Trafienie w cache \u2013 szybko i tanio \u26A1' : 'Świeży wynik z Google \u2013 zapisano do cache', data.from_cache ? 'ok' : 'warn');
|
|
} catch (err) {
|
|
console.error(err);
|
|
setStatus('Błąd: ' + (err?.message || err), 'err');
|
|
} finally {
|
|
btn.disabled = false;
|
|
}
|
|
});
|
|
|
|
$('#clear').addEventListener('click', () => {
|
|
$('#query').value = '';
|
|
clearResult();
|
|
setStatus('');
|
|
$('#query').focus();
|
|
});
|
|
|
|
$$('.examples a').forEach(a => a.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
const q = e.currentTarget.getAttribute('data-q');
|
|
$('#query').value = q;
|
|
$('#geo-form').dispatchEvent(new Event('submit'));
|
|
}));
|
|
|
|
// autofocus
|
|
$('#query').focus();
|
|
</script>
|
|
</body>
|
|
</html>
|