togethere.cloud/public_html/administration/matches/all/index.php

580 lines
29 KiB
PHP

<?php
require_once __DIR__ . '/../../includes/auth.php';
require_once __DIR__ . '/../../includes/config.php';
require_once __DIR__ . '/../../includes/header.php';
require_once __DIR__ . '/../../includes/sidebar.php';
?>
<div class="admin-content">
<style>
.admin-page-title{font-size:24px;font-weight:600;color:#23282d;margin-bottom:20px;padding-bottom:10px;border-bottom:2px solid #0073aa}
.admin-content-box{background:#fff;border:1px solid #ddd;border-radius:4px;padding:24px;margin-top:20px;box-shadow:0 1px 3px rgba(0,0,0,.1)}
.section-wrap{margin-bottom:32px}
.section-head{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:4px;cursor:pointer;user-select:none;font-weight:700;font-size:14px}
.section-head .toggle-arrow{font-size:12px;color:#888;transition:transform .2s}
.section-head.collapsed .toggle-arrow{transform:rotate(-90deg)}
.sh-live{background:#fff2f2;border:1px solid #f5c6cb;color:#721c24}
.sh-planned{background:#f0f6ff;border:1px solid #b8d4f5;color:#0c4a8a}
.sh-ended{background:#f0fff4;border:1px solid #b2dfdb;color:#155724}
.sh-results{background:#fafafa;border:1px solid #ddd;color:#333}
.section-body{padding:14px 0}
.section-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:700;margin-left:8px}
.sb-live{background:#dc3545;color:#fff}
.sb-planned{background:#0073aa;color:#fff}
.sb-ended{background:#28a745;color:#fff}
.filters-bar{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;align-items:center}
.filters-bar input,.filters-bar select{padding:6px 10px;border:1px solid #ddd;border-radius:4px;font-size:12px}
.filters-bar button{padding:6px 12px;background:#6c757d;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:12px}
.filters-bar button:hover{background:#5a6268}
.matches-table{width:100%;border-collapse:collapse}
.matches-table thead{background:#f5f5f5;border-bottom:2px solid #ddd}
.matches-table th{padding:9px 11px;text-align:left;font-weight:600;color:#333;font-size:12px;cursor:pointer;user-select:none}
.matches-table th:hover{background:#e8e8e8}
.matches-table td{padding:8px 11px;border-bottom:1px solid #eee;font-size:12px}
.matches-table tbody tr:hover{background:#f9f9f9}
.badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;text-transform:uppercase}
.badge-live{background:#dc3545;color:#fff}
.badge-end{background:#28a745;color:#fff}
.badge-planned{background:#0073aa;color:#fff}
.badge-normal{background:#28a745;color:#fff}
.badge-disconnect{background:#dc3545;color:#fff}
.badge-both-disconnect{background:#6f42c1;color:#fff}
.badge-forfeit{background:#e83e8c;color:#fff}
.badge-timeout{background:#fd7e14;color:#fff}
.badge-other{background:#6c757d;color:#fff}
.no-data{text-align:center;padding:20px;color:#aaa;font-size:12px}
.loading-row td{text-align:center;padding:20px;color:#666;font-size:12px}
.total-info{font-size:11px;color:#888;margin-bottom:8px}
.pagination{display:flex;justify-content:center;gap:5px;margin-top:14px;flex-wrap:wrap}
.pagination button,.pagination span{padding:5px 10px;border:1px solid #ddd;border-radius:4px;cursor:pointer;background:#fff;font-size:12px}
.pagination button:hover{background:#0073aa;color:#fff;border-color:#0073aa}
.pagination .active{background:#0073aa;color:#fff;border-color:#0073aa}
.error-box{background:#f8d7da;color:#721c24;padding:10px 12px;border-radius:4px;border:1px solid #f5c6cb;font-size:12px;margin-bottom:10px}
.btn-del{background:#dc3545;color:#fff;border:none;border-radius:3px;padding:3px 9px;font-size:11px;cursor:pointer;line-height:1.4}
.btn-del:hover{background:#b02a37}
@media(max-width:768px){
.matches-table{font-size:11px}
.matches-table th,.matches-table td{padding:5px 6px}
.filters-bar{flex-direction:column}
.filters-bar input,.filters-bar select,.filters-bar button{width:100%}
}
</style>
<h1 class="admin-page-title">Mecze online</h1>
<div class="admin-content-box">
<!-- ======================================================= -->
<!-- SEKCJA 1: AKTYWNE (live) -->
<!-- ======================================================= -->
<div class="section-wrap" id="wrap-live">
<div class="section-head sh-live" onclick="toggleSection('live')">
<span>Aktywne mecze <span class="section-badge sb-live" id="badge-live">0</span></span>
<span class="toggle-arrow" id="arrow-live">&#9660;</span>
</div>
<div class="section-body" id="body-live">
<div class="filters-bar">
<input type="text" id="live-search" placeholder="Szukaj gracza / ID..." oninput="filterSection('live')" style="min-width:180px">
<select id="live-disc" onchange="filterSection('live')">
<option value="">Wszystkie dyscypliny</option>
<option value="ping-pong">Ping-Pong</option>
<option value="table-football">Pilkarzyki</option>
<option value="rock-paper-scissors">Kamien, papier, nozyce</option>
</select>
<button onclick="clearFilters('live')">Resetuj</button>
</div>
<div id="live-error"></div>
<div id="live-empty" class="no-data" style="display:none">Brak aktywnych meczow</div>
<table class="matches-table" id="live-table" style="display:none">
<thead><tr>
<th>#</th><th>Dyscyplina</th><th>Gracz 1</th><th>Gracz 2</th><th>Wynik</th><th>Rozpoczeto</th>
</tr></thead>
<tbody id="live-tbody"></tbody>
</table>
</div>
</div>
<!-- ======================================================= -->
<!-- SEKCJA 2: ZAPLANOWANE (planned) -->
<!-- ======================================================= -->
<div class="section-wrap" id="wrap-planned">
<div class="section-head sh-planned" onclick="toggleSection('planned')">
<span>Zaplanowane mecze <span class="section-badge sb-planned" id="badge-planned">0</span></span>
<span class="toggle-arrow" id="arrow-planned">&#9660;</span>
</div>
<div class="section-body" id="body-planned">
<div class="filters-bar">
<input type="text" id="planned-search" placeholder="Szukaj gracza / ID..." oninput="filterSection('planned')" style="min-width:180px">
<select id="planned-disc" onchange="filterSection('planned')">
<option value="">Wszystkie dyscypliny</option>
<option value="ping-pong">Ping-Pong</option>
<option value="table-football">Pilkarzyki</option>
<option value="rock-paper-scissors">Kamien, papier, nozyce</option>
</select>
<button onclick="clearFilters('planned')">Resetuj</button>
</div>
<div id="planned-error"></div>
<div id="planned-empty" class="no-data" style="display:none">Brak zaplanowanych meczow</div>
<table class="matches-table" id="planned-table" style="display:none">
<thead><tr>
<th>#</th><th>Dyscyplina</th><th>Gracz 1</th><th>Gracz 2</th><th>Wynik</th><th>Rozpoczeto</th>
</tr></thead>
<tbody id="planned-tbody"></tbody>
</table>
</div>
</div>
<!-- ======================================================= -->
<!-- SEKCJA 3: ZAKONCZONE SESJE (end, z tabeli matches) -->
<!-- ======================================================= -->
<div class="section-wrap" id="wrap-ended">
<div class="section-head sh-ended" onclick="toggleSection('ended')">
<span>Zakonczone sesje <span class="section-badge sb-ended" id="badge-ended">0</span></span>
<span class="toggle-arrow" id="arrow-ended">&#9660;</span>
</div>
<div class="section-body" id="body-ended">
<div class="filters-bar">
<input type="text" id="ended-search" placeholder="Szukaj gracza / ID..." oninput="filterSection('ended')" style="min-width:180px">
<select id="ended-disc" onchange="filterSection('ended')">
<option value="">Wszystkie dyscypliny</option>
<option value="ping-pong">Ping-Pong</option>
<option value="table-football">Pilkarzyki</option>
<option value="rock-paper-scissors">Kamien, papier, nozyce</option>
</select>
<input type="date" id="ended-date-from" onchange="filterSection('ended')" title="Data od">
<input type="date" id="ended-date-to" onchange="filterSection('ended')" title="Data do">
<button onclick="clearFilters('ended')">Resetuj</button>
</div>
<div id="ended-error"></div>
<div id="ended-empty" class="no-data" style="display:none">Brak zakonczonch sesji</div>
<table class="matches-table" id="ended-table" style="display:none">
<thead><tr>
<th>#</th><th>Dyscyplina</th><th>Gracz 1</th><th>Gracz 2</th><th>Wynik</th><th>Rozpoczeto</th><th>Zakonczone</th><th></th>
</tr></thead>
<tbody id="ended-tbody"></tbody>
</table>
</div>
</div>
<!-- ======================================================= -->
<!-- SEKCJA 4: WYNIKI MECZOW (match_results, paginowane) -->
<!-- ======================================================= -->
<div class="section-wrap" id="wrap-results">
<div class="section-head sh-results" onclick="toggleSection('results')">
<span>Wyniki meczow <span class="section-badge" id="badge-results" style="background:#555;color:#fff">0</span></span>
<span class="toggle-arrow" id="arrow-results">&#9660;</span>
</div>
<div class="section-body" id="body-results">
<div class="filters-bar">
<input type="text" id="res-user" placeholder="Szukaj gracza..." oninput="debounceResults()" style="min-width:160px">
<select id="res-disc" onchange="loadResults(1)">
<option value="">Wszystkie dyscypliny</option>
<option value="ping-pong">Ping-Pong</option>
<option value="table-football">Pilkarzyki</option>
<option value="rock-paper-scissors">Kamien, papier, nozyce</option>
</select>
<select id="res-mode" onchange="loadResults(1)">
<option value="">Wszystkie tryby</option>
<option value="1v1">1v1</option>
</select>
<select id="res-reason" onchange="loadResults(1)">
<option value="">Wszystkie zakonczenia</option>
<option value="normal">Normalny</option>
<option value="disconnect">Rozlaczenie</option>
<option value="timeout">Timeout</option>
</select>
<input type="date" id="res-date-from" onchange="loadResults(1)" title="Data od">
<input type="date" id="res-date-to" onchange="loadResults(1)" title="Data do">
<button onclick="clearFilters('results')">Resetuj</button>
</div>
<div id="res-total" class="total-info" style="display:none"></div>
<div id="res-error"></div>
<div id="res-empty" class="no-data" style="display:none">Brak wynikow meczow</div>
<table class="matches-table" id="res-table" style="display:none">
<thead><tr>
<th onclick="doSort('id')">#</th>
<th onclick="doSort('discipline')">Dyscyplina</th>
<th onclick="doSort('winner_username')">Zwyciezca</th>
<th onclick="doSort('loser_username')">Przegrany</th>
<th>Wynik</th>
<th onclick="doSort('reason')">Zakonczenie</th>
<th onclick="doSort('ended_at')">Zakonczone</th>
<th></th>
</tr></thead>
<tbody id="res-tbody"></tbody>
</table>
<div class="pagination" id="res-pages" style="display:none"></div>
</div>
</div>
</div><!-- /admin-content-box -->
</div><!-- /admin-content -->
<script>
// ─── STATE ──────────────────────────────────────────────────────────────────
var rawData = { live: [], planned: [], ended: [], results: [] };
var resSort = 'ended_at';
var resSortOrder = 'DESC';
var resPage = 1;
var resDebounce = null;
var collapsed = { live: false, planned: false, ended: false, results: false };
// ─── UTILS ──────────────────────────────────────────────────────────────────
function esc(s) {
return String(s == null ? '' : s)
.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
function fmt(dt) {
if (!dt) return '-';
var d = new Date(dt);
return d.toLocaleDateString('pl-PL') + ' ' + d.toLocaleTimeString('pl-PL',{hour:'2-digit',minute:'2-digit'});
}
function badgeClass(reason) {
if (!reason) return 'badge-other';
switch (reason.toLowerCase()) {
case 'normal': return 'badge-normal';
case 'sets': return 'badge-normal';
case 'disconnect': return 'badge-disconnect';
case 'both_disconnect': return 'badge-both-disconnect';
case 'timeout': return 'badge-timeout';
default:
if (reason.startsWith('forfeit_')) return 'badge-forfeit';
return 'badge-other';
}
}
function val(id) { return document.getElementById(id).value; }
function show(id) { document.getElementById(id).style.display = ''; }
function hide(id) { document.getElementById(id).style.display = 'none'; }
function setText(id, t) { document.getElementById(id).textContent = t; }
function setHTML(id, h) { document.getElementById(id).innerHTML = h; }
// ─── TOGGLE SECTIONS ────────────────────────────────────────────────────────
function toggleSection(key) {
collapsed[key] = !collapsed[key];
var body = document.getElementById('body-' + key);
var arrow = document.getElementById('arrow-' + key);
var head = document.querySelector('.sh-' + (key === 'results' ? 'results' : key));
body.style.display = collapsed[key] ? 'none' : '';
if (arrow) arrow.style.transform = collapsed[key] ? 'rotate(-90deg)' : '';
}
// ─── CLIENT-SIDE FILTER (live / planned / ended) ────────────────────────────
function filterSection(key) {
var search = val(key + '-search').toLowerCase();
var disc = val(key + '-disc');
var dfrom = key === 'ended' ? val('ended-date-from') : '';
var dto = key === 'ended' ? val('ended-date-to') : '';
var source = key === 'ended' ? rawData.ended : (key === 'live' ? rawData.live : rawData.planned);
var filtered = source.filter(function(m) {
var u1 = (m.user1_username || '').toLowerCase();
var u2 = (m.user2_username || '').toLowerCase();
var id = String(m.id);
if (search && u1.indexOf(search) < 0 && u2.indexOf(search) < 0 && id.indexOf(search) < 0) return false;
if (disc && m.discipline !== disc) return false;
if (dfrom && m.started_at && m.started_at.slice(0,10) < dfrom) return false;
if (dto && m.started_at && m.started_at.slice(0,10) > dto) return false;
return true;
});
renderSessionTable(key, filtered);
}
function clearFilters(key) {
if (key === 'live' || key === 'planned') { document.getElementById(key+'-search').value=''; document.getElementById(key+'-disc').value=''; }
if (key === 'ended') { ['ended-search','ended-disc','ended-date-from','ended-date-to'].forEach(function(id){document.getElementById(id).value='';}); }
if (key === 'results'){ ['res-user','res-disc','res-mode','res-reason','res-date-from','res-date-to'].forEach(function(id){document.getElementById(id).value='';}); loadResults(1); return; }
filterSection(key);
}
// ─── RENDER SESSION TABLE (live / planned / ended) ──────────────────────────
function renderSessionTable(key, rows) {
var tbody = document.getElementById(key + '-tbody');
var table = document.getElementById(key + '-table');
var empty = document.getElementById(key + '-empty');
tbody.innerHTML = '';
if (rows.length === 0) {
table.style.display = 'none';
empty.style.display = '';
return;
}
empty.style.display = 'none';
rows.forEach(function(m) {
var u1 = esc(m.user1_username || '');
var u2 = esc(m.user2_username || '');
var tr = document.createElement('tr');
var cells =
'<td><strong>' + esc(m.id) + '</strong></td>' +
'<td>' + esc(m.discipline) + '</td>' +
'<td>' + (u1 ? u1 + ' ' : '') + '<small style="color:#999">#' + esc(m.user1_id) + '</small></td>' +
'<td>' + (u2 ? u2 + ' ' : '') + '<small style="color:#999">#' + esc(m.user2_id) + '</small></td>' +
'<td><strong>' + esc(m.score || '0:0') + '</strong></td>' +
'<td style="white-space:nowrap">' + fmt(m.started_at) + '</td>';
if (key === 'ended') {
cells += '<td style="white-space:nowrap">' + (m.ended_at ? fmt(m.ended_at) : '-') + '</td>';
cells += '<td><button class="btn-del" onclick="deleteMatch(' + esc(m.id) + ', this)">Usun</button></td>';
}
tr.innerHTML = cells;
tbody.appendChild(tr);
});
table.style.display = 'table';
}
// ─── LOAD ALL (initial + live refresh) ───────────────────────────────────────
function loadAll() {
console.log('[matches] loadAll() start');
// Show loading state in results section
document.getElementById('res-empty').style.display = 'none';
document.getElementById('res-table').style.display = 'none';
document.getElementById('res-error').innerHTML = '';
document.getElementById('res-total').innerHTML = '<em style="color:#999;font-size:11px">Ladowanie...</em>';
document.getElementById('res-total').style.display = '';
var url = '/api/admin_match_results.php?page=' + resPage + '&limit=25&sortBy=' + resSort + '&sortOrder=' + resSortOrder + buildResParams();
console.log('[matches] fetch URL:', url);
fetch(url)
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
.then(function(data) {
console.log('[matches] response:', data);
document.getElementById('res-total').innerHTML = '';
document.getElementById('res-total').style.display = 'none';
if (!data.success) {
showError('global', data.error || 'Blad');
showError('res', data.error || 'Blad');
return;
}
// Store raw data
rawData.live = data.live || [];
rawData.planned = data.planned || [];
rawData.ended = data.ended_sessions || [];
// Update badges
setText('badge-live', rawData.live.length);
setText('badge-planned', rawData.planned.length);
setText('badge-ended', rawData.ended.length);
setText('badge-results', data.pagination ? data.pagination.totalRecords : 0);
// Render sessions
filterSection('live');
filterSection('planned');
filterSection('ended');
// Render results
console.log('[matches] results count:', data.results ? data.results.length : 'null', 'total:', data.pagination ? data.pagination.totalRecords : 'no pag');
renderResults(data.results || [], data.pagination);
})
.catch(function(err) {
console.error('[matches] fetch error:', err);
document.getElementById('res-total').style.display = 'none';
showError('global', 'Blad ladowania: ' + err.message);
showError('res', 'Blad ladowania: ' + err.message);
});
}
// ─── LOAD RESULTS (paginated, server-side) ───────────────────────────────────
function buildResParams() {
var p = '';
if (val('res-user')) p += '&user=' + encodeURIComponent(val('res-user'));
if (val('res-disc')) p += '&discipline=' + encodeURIComponent(val('res-disc'));
if (val('res-mode')) p += '&mode=' + encodeURIComponent(val('res-mode'));
if (val('res-reason')) p += '&reason=' + encodeURIComponent(val('res-reason'));
if (val('res-date-from')) p += '&date_from=' + encodeURIComponent(val('res-date-from'));
if (val('res-date-to')) p += '&date_to=' + encodeURIComponent(val('res-date-to'));
return p;
}
function loadResults(page) {
resPage = page || 1;
var url = '/api/admin_match_results.php?page=' + resPage + '&limit=25&sortBy=' + resSort + '&sortOrder=' + resSortOrder + buildResParams();
fetch(url)
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
.then(function(data) {
if (!data.success) { showError('res', data.error || 'Blad'); return; }
rawData.live = data.live || [];
rawData.planned = data.planned || [];
rawData.ended = data.ended_sessions || [];
setText('badge-live', rawData.live.length);
setText('badge-planned', rawData.planned.length);
setText('badge-ended', rawData.ended.length);
setText('badge-results', data.pagination ? data.pagination.totalRecords : 0);
filterSection('live');
filterSection('planned');
filterSection('ended');
renderResults(data.results || [], data.pagination);
})
.catch(function(err) { showError('res', 'Blad: ' + err.message); });
}
function debounceResults() {
clearTimeout(resDebounce);
resDebounce = setTimeout(function() { loadResults(1); }, 400);
}
function doSort(col) {
if (resSort === col) {
resSortOrder = resSortOrder === 'DESC' ? 'ASC' : 'DESC';
} else {
resSort = col;
resSortOrder = 'DESC';
}
loadResults(1);
}
// ─── RENDER RESULTS TABLE ────────────────────────────────────────────────────
function renderResults(rows, pag) {
var tbody = document.getElementById('res-tbody');
var table = document.getElementById('res-table');
var empty = document.getElementById('res-empty');
var total = document.getElementById('res-total');
var pages = document.getElementById('res-pages');
tbody.innerHTML = '';
pages.innerHTML = '';
pages.style.display = 'none';
empty.style.display = 'none';
table.style.display = 'none';
total.style.display = 'none';
if (pag) {
total.textContent = 'Lacznie: ' + pag.totalRecords + ' wynikow';
total.style.display = '';
setText('badge-results', pag.totalRecords);
}
if (!rows || rows.length === 0) {
empty.style.display = '';
return;
}
rows.forEach(function(m) {
var sets = (m.sets_winner != null && m.sets_loser != null)
? ' <small>(' + esc(m.sets_winner) + ':' + esc(m.sets_loser) + ' set.)</small>' : '';
var tr = document.createElement('tr');
tr.innerHTML =
'<td><strong>' + esc(m.id) + '</strong></td>' +
'<td>' + esc(m.discipline) + ' <small style="color:#999">' + esc(m.mode) + '</small></td>' +
'<td style="color:#155724;font-weight:600">W: ' + esc(m.winner_username) + ' <small style="color:#999">#' + esc(m.winner_user_id) + '</small></td>' +
'<td style="color:#721c24">L: ' + esc(m.loser_username) + ' <small style="color:#999">#' + esc(m.loser_user_id) + '</small></td>' +
'<td>' + esc(m.score) + sets + '</td>' +
'<td><span class="badge ' + badgeClass(m.reason) + '">' + esc(m.reason || '?') + '</span></td>' +
'<td style="white-space:nowrap">' + fmt(m.ended_at) + '</td>' +
'<td><button class="btn-del" onclick="deleteResult(' + esc(m.id) + ', this)">Usun</button></td>';
tbody.appendChild(tr);
});
table.style.display = 'table';
if (pag && pag.totalPages > 1) {
renderPagination(pag);
pages.style.display = 'flex';
}
}
function renderPagination(p) {
var c = document.getElementById('res-pages');
c.innerHTML = '';
if (p.hasPreviousPage) {
var b = document.createElement('button');
b.textContent = '< Poprzednia';
b.onclick = (function(pg) { return function() { loadResults(pg); }; })(p.currentPage - 1);
c.appendChild(b);
}
var start = Math.max(1, p.currentPage - 2);
var end = Math.min(p.totalPages, p.currentPage + 2);
for (var i = start; i <= end; i++) {
var b2 = document.createElement('button');
b2.textContent = i;
if (i === p.currentPage) b2.classList.add('active');
b2.onclick = (function(_i) { return function() { loadResults(_i); }; })(i);
c.appendChild(b2);
}
if (p.hasNextPage) {
var b3 = document.createElement('button');
b3.textContent = 'Nastepna >';
b3.onclick = (function(pg) { return function() { loadResults(pg); }; })(p.currentPage + 1);
c.appendChild(b3);
}
}
// ─── DELETE ──────────────────────────────────────────────────────────────────
function deleteMatch(id, btn) {
if (!confirm('Usunac mecz #' + id + ' z bazy?')) return;
btn.disabled = true;
btn.textContent = '...';
var fd = new FormData();
fd.append('type', 'match');
fd.append('id', id);
fetch('/api/admin_delete_match.php', { method: 'POST', body: fd })
.then(function(r) { return r.json(); })
.then(function(d) {
if (!d.success) { alert('Blad: ' + (d.error || '?')); btn.disabled = false; btn.textContent = 'Usun'; return; }
var tr = btn.closest('tr');
if (tr) tr.remove();
rawData.ended = rawData.ended.filter(function(m) { return String(m.id) !== String(id); });
setText('badge-ended', rawData.ended.length);
})
.catch(function(e) { alert('Blad: ' + e.message); btn.disabled = false; btn.textContent = 'Usun'; });
}
function deleteResult(id, btn) {
if (!confirm('Usunac wynik #' + id + ' z bazy?')) return;
btn.disabled = true;
btn.textContent = '...';
var fd = new FormData();
fd.append('type', 'result');
fd.append('id', id);
fetch('/api/admin_delete_match.php', { method: 'POST', body: fd })
.then(function(r) { return r.json(); })
.then(function(d) {
if (!d.success) { alert('Blad: ' + (d.error || '?')); btn.disabled = false; btn.textContent = 'Usun'; return; }
var tr = btn.closest('tr');
if (tr) tr.remove();
loadResults(resPage);
})
.catch(function(e) { alert('Blad: ' + e.message); btn.disabled = false; btn.textContent = 'Usun'; });
}
// ─── ERRORS ──────────────────────────────────────────────────────────────────
function showError(key, msg) {
var id = key === 'global' ? 'live-error' : 'res-error';
document.getElementById(id).innerHTML = '<div class="error-box">' + esc(msg) + '</div>';
}
// ─── INIT ────────────────────────────────────────────────────────────────────
console.log('[matches] script zaladowany');
document.addEventListener('DOMContentLoaded', function() {
console.log('[matches] DOMContentLoaded');
loadAll();
// Auto-refresh live section every 10s
setInterval(function() {
fetch('/api/admin_match_results.php?page=1&limit=25')
.then(function(r) { return r.ok ? r.json() : null; })
.then(function(data) {
if (!data || !data.success) return;
rawData.live = data.live || [];
rawData.planned = data.planned || [];
rawData.ended = data.ended_sessions || [];
setText('badge-live', rawData.live.length);
setText('badge-planned', rawData.planned.length);
setText('badge-ended', rawData.ended.length);
filterSection('live');
filterSection('planned');
filterSection('ended');
// odswiezaj tez wyniki jesli jestesmy na stronie 1
if (resPage === 1) renderResults(data.results || [], data.pagination || {});
})
.catch(function() {});
}, 2000);
});
</script>
<?php
require_once __DIR__ . '/../../includes/footer.php';
?>