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

457 lines
15 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: 30px;
margin-top: 20px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.matches-controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
gap: 15px;
flex-wrap: wrap;
}
.matches-filters {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.matches-filters input,
.matches-filters select {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.matches-filters button {
padding: 8px 16px;
background-color: #0073aa;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
}
.matches-filters button:hover {
background-color: #005a87;
}
.matches-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.matches-table thead {
background-color: #f5f5f5;
border-bottom: 2px solid #ddd;
}
.matches-table th {
padding: 12px;
text-align: left;
font-weight: 600;
color: #333;
cursor: pointer;
user-select: none;
}
.matches-table th:hover {
background-color: #e8e8e8;
}
.matches-table td {
padding: 12px;
border-bottom: 1px solid #ddd;
}
.matches-table tbody tr:hover {
background-color: #f9f9f9;
}
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
}
.status-live {
background-color: #ff4444;
color: white;
}
.status-planned {
background-color: #0073aa;
color: white;
}
.status-end {
background-color: #28a745;
color: white;
}
.pagination {
display: flex;
justify-content: center;
gap: 10px;
margin-top: 20px;
}
.pagination button,
.pagination span {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
background: white;
transition: all 0.2s;
}
.pagination button:hover {
background-color: #0073aa;
color: white;
border-color: #0073aa;
}
.pagination button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination .active {
background-color: #0073aa;
color: white;
border-color: #0073aa;
}
.loading {
text-align: center;
padding: 40px;
color: #666;
}
.error-message {
background-color: #f8d7da;
color: #721c24;
padding: 12px;
border-radius: 4px;
margin-bottom: 20px;
border: 1px solid #f5c6cb;
}
.no-data {
text-align: center;
padding: 40px;
color: #999;
}
@media (max-width: 768px) {
.matches-table {
font-size: 12px;
}
.matches-table th,
.matches-table td {
padding: 8px;
}
.matches-controls {
flex-direction: column;
align-items: stretch;
}
.matches-filters {
flex-direction: column;
}
.matches-filters input,
.matches-filters select,
.matches-filters button {
width: 100%;
}
}
</style>
<h1 class="admin-page-title">🎮 Wszystkie mecze</h1>
<div class="admin-content-box">
<!-- Kontrolki filtrowania -->
<div class="matches-controls">
<div class="matches-filters">
<select id="statusFilter" onchange="applyFilters()">
<option value="">Wszystkie statusy</option>
<option value="planned">Zaplanowane</option>
<option value="live">Trwające</option>
<option value="end">Zakończone</option>
</select>
<select id="platformFilter" onchange="applyFilters()">
<option value="">Wszystkie platformy</option>
<option value="PC">PC</option>
<option value="PSP">PSP</option>
<option value="android">Android</option>
<option value="iphone">iPhone</option>
</select>
<select id="matchTypeFilter" onchange="applyFilters()">
<option value="">Wszystkie typy</option>
<option value="liga">Liga</option>
<option value="turniej">Turniej</option>
<option value="przyjacielski">Przyjacielski</option>
</select>
<button onclick="resetFilters()">Resetuj filtry</button>
</div>
</div>
<!-- Tabela z meczami -->
<div id="loadingIndicator" class="loading" style="display: none;">
⏳ Wczytywanie danych...
</div>
<div id="errorContainer" style="display: none;"></div>
<table class="matches-table" id="matchesTable" style="display: none;">
<thead>
<tr>
<th onclick="sortBy('ID')">ID ↕️</th>
<th onclick="sortBy('Team1_ID')">Drużyna 1 ↕️</th>
<th onclick="sortBy('Team2_ID')">Drużyna 2 ↕️</th>
<th onclick="sortBy('StartTime')">Data/Czas ↕️</th>
<th onclick="sortBy('Status')">Status ↕️</th>
<th>Wynik</th>
<th>Platforma</th>
<th>Typ</th>
</tr>
</thead>
<tbody id="matchesBody">
</tbody>
</table>
<div id="noDataContainer" class="no-data" style="display: none;">
Brak meczów do wyświetlenia
</div>
<!-- Paginacja -->
<div class="pagination" id="paginationContainer" style="display: none;">
</div>
</div>
</div>
<script>
let currentPage = 1;
let currentSort = 'StartTime';
let currentSortOrder = 'ASC';
function mapStatusClass(status) {
const statusLower = status.toLowerCase();
if (statusLower.includes('live') || statusLower.includes('trakcie')) return 'status-live';
if (statusLower.includes('planned') || statusLower.includes('zaplanow')) return 'status-planned';
if (statusLower.includes('end') || statusLower.includes('zakończ')) return 'status-end';
return 'status-planned';
}
function loadMatches(page = 1) {
const statusFilter = document.getElementById('statusFilter').value;
const platformFilter = document.getElementById('platformFilter').value;
const matchTypeFilter = document.getElementById('matchTypeFilter').value;
let url = '/api/getMatches.php?page=' + page + '&limit=20&sortBy=' + currentSort + '&sortOrder=' + currentSortOrder;
if (statusFilter) url += '&status=' + encodeURIComponent(statusFilter);
if (platformFilter) url += '&platform=' + encodeURIComponent(platformFilter);
if (matchTypeFilter) url += '&matchType=' + encodeURIComponent(matchTypeFilter);
document.getElementById('loadingIndicator').style.display = 'block';
document.getElementById('matchesTable').style.display = 'none';
document.getElementById('noDataContainer').style.display = 'none';
document.getElementById('errorContainer').style.display = 'none';
document.getElementById('paginationContainer').style.display = 'none';
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Błąd HTTP ' + response.status);
}
return response.json();
})
.then(data => {
document.getElementById('loadingIndicator').style.display = 'none';
if (!data.success) {
showError(data.error || 'Nieznany błąd');
return;
}
if (data.data.length === 0) {
document.getElementById('noDataContainer').style.display = 'block';
return;
}
displayMatches(data.data);
displayPagination(data.pagination);
document.getElementById('matchesTable').style.display = 'table';
document.getElementById('paginationContainer').style.display = 'flex';
currentPage = page;
})
.catch(error => {
document.getElementById('loadingIndicator').style.display = 'none';
showError('Błąd podczas ładowania meczów: ' + error.message);
});
}
function displayMatches(matches) {
const tbody = document.getElementById('matchesBody');
tbody.innerHTML = '';
matches.forEach(match => {
const row = document.createElement('tr');
// Formatowanie daty
const startTime = new Date(match.StartTime);
const dateStr = startTime.toLocaleDateString('pl-PL') + ' ' + startTime.toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' });
row.innerHTML = `
<td><strong>${match.ID}</strong></td>
<td>${match.Team1_ID}</td>
<td>${match.Team2_ID}</td>
<td>${dateStr}</td>
<td><span class="status-badge ${mapStatusClass(match.Status)}">${match.Status}</span></td>
<td>${match.Score || '-'}</td>
<td>${match.Platform || '-'}</td>
<td>${match.MatchType || '-'}</td>
`;
tbody.appendChild(row);
});
}
function displayPagination(pagination) {
const container = document.getElementById('paginationContainer');
container.innerHTML = '';
// Poprzednia strona
if (pagination.hasPreviousPage) {
const prevBtn = document.createElement('button');
prevBtn.textContent = '← Poprzednia';
prevBtn.onclick = () => loadMatches(pagination.currentPage - 1);
container.appendChild(prevBtn);
}
// Numery stron
const startPage = Math.max(1, pagination.currentPage - 2);
const endPage = Math.min(pagination.totalPages, pagination.currentPage + 2);
if (startPage > 1) {
const firstBtn = document.createElement('button');
firstBtn.textContent = '1';
firstBtn.onclick = () => loadMatches(1);
container.appendChild(firstBtn);
if (startPage > 2) {
const dots = document.createElement('span');
dots.textContent = '...';
container.appendChild(dots);
}
}
for (let i = startPage; i <= endPage; i++) {
const btn = document.createElement('button');
btn.textContent = i;
if (i === pagination.currentPage) {
btn.classList.add('active');
}
btn.onclick = () => loadMatches(i);
container.appendChild(btn);
}
if (endPage < pagination.totalPages) {
if (endPage < pagination.totalPages - 1) {
const dots = document.createElement('span');
dots.textContent = '...';
container.appendChild(dots);
}
const lastBtn = document.createElement('button');
lastBtn.textContent = pagination.totalPages;
lastBtn.onclick = () => loadMatches(pagination.totalPages);
container.appendChild(lastBtn);
}
// Następna strona
if (pagination.hasNextPage) {
const nextBtn = document.createElement('button');
nextBtn.textContent = 'Następna →';
nextBtn.onclick = () => loadMatches(pagination.currentPage + 1);
container.appendChild(nextBtn);
}
}
function sortBy(column) {
if (currentSort === column) {
currentSortOrder = currentSortOrder === 'ASC' ? 'DESC' : 'ASC';
} else {
currentSort = column;
currentSortOrder = 'ASC';
}
loadMatches(1);
}
function applyFilters() {
loadMatches(1);
}
function resetFilters() {
document.getElementById('statusFilter').value = '';
document.getElementById('platformFilter').value = '';
document.getElementById('matchTypeFilter').value = '';
loadMatches(1);
}
function showError(message) {
const errorContainer = document.getElementById('errorContainer');
errorContainer.innerHTML = '<div class="error-message">' + message + '</div>';
errorContainer.style.display = 'block';
}
// Załaduj mecze przy ładowaniu strony
document.addEventListener('DOMContentLoaded', function() {
loadMatches(1);
});
</script>
<?php
require_once __DIR__ . '/../../includes/footer.php';
?>