1565 lines
42 KiB
HTML
1565 lines
42 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<title>Tournament Management</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<style>
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html, body {
|
||
margin: 0;
|
||
padding: 0;
|
||
background: #f5f5f5;
|
||
font-family: Arial, sans-serif;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.navbar {
|
||
background: white;
|
||
color: black;
|
||
padding: 15px 25px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
border-bottom: 2px solid #ccc;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.navbar-title {
|
||
font-size: 1.8rem;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.navbar-controls {
|
||
display: flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
}
|
||
|
||
.nav-btn {
|
||
background: #f8f9fa;
|
||
border: 2px solid #e9ecef;
|
||
cursor: pointer;
|
||
padding: 12px 20px;
|
||
border-radius: 8px;
|
||
transition: all 0.2s ease;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||
color: #333;
|
||
text-decoration: none;
|
||
font-weight: bold;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.nav-btn:hover {
|
||
background: #e9ecef;
|
||
border-color: #007bff;
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||
transform: translateY(-1px);
|
||
color: #007bff;
|
||
}
|
||
|
||
.nav-btn.primary {
|
||
background: #007bff;
|
||
border-color: #0056b3;
|
||
color: white;
|
||
}
|
||
|
||
.nav-btn.primary:hover {
|
||
background: #0056b3;
|
||
color: white;
|
||
}
|
||
|
||
.nav-btn.success {
|
||
background: #28a745;
|
||
border-color: #1e7e34;
|
||
color: white;
|
||
}
|
||
|
||
.nav-btn.success:hover {
|
||
background: #1e7e34;
|
||
color: white;
|
||
}
|
||
|
||
.nav-btn.danger {
|
||
background: #dc3545;
|
||
border-color: #c82333;
|
||
color: white;
|
||
}
|
||
|
||
.nav-btn.danger:hover {
|
||
background: #c82333;
|
||
color: white;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 30px 20px;
|
||
}
|
||
|
||
.section {
|
||
background: white;
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
padding: 25px;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 1.5rem;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20px;
|
||
border-bottom: 3px solid #007bff;
|
||
padding-bottom: 8px;
|
||
}
|
||
|
||
/* League Status */
|
||
.league-status {
|
||
text-align: center;
|
||
padding: 30px;
|
||
}
|
||
|
||
.league-active {
|
||
color: #28a745;
|
||
font-size: 1.4rem;
|
||
font-weight: bold;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.league-inactive {
|
||
color: #6c757d;
|
||
font-size: 1.2rem;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.league-info {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||
gap: 15px;
|
||
}
|
||
|
||
.info-item {
|
||
background: white;
|
||
padding: 15px;
|
||
border-radius: 6px;
|
||
border: 1px solid #e9ecef;
|
||
text-align: center;
|
||
}
|
||
|
||
.info-label {
|
||
font-size: 0.9rem;
|
||
color: #666;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.info-value {
|
||
font-size: 1.3rem;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
/* Tournament Type Selection */
|
||
.tournament-type-selection {
|
||
background: #f8f9fa;
|
||
border: 2px solid #e9ecef;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.type-title {
|
||
font-size: 1.1rem;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.type-options {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 15px;
|
||
}
|
||
|
||
.type-option {
|
||
background: white;
|
||
border: 2px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
text-align: center;
|
||
}
|
||
|
||
.type-option:hover {
|
||
border-color: #007bff;
|
||
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.15);
|
||
}
|
||
|
||
.type-option.selected {
|
||
border-color: #007bff;
|
||
background: #f0f8ff;
|
||
}
|
||
|
||
.type-option input[type="radio"] {
|
||
margin-right: 10px;
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.type-name {
|
||
font-size: 1.2rem;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.type-description {
|
||
font-size: 0.9rem;
|
||
color: #666;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
/* Joker Management */
|
||
.joker-section {
|
||
background: #fff3cd;
|
||
border: 2px solid #ffeaa7;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.joker-title {
|
||
font-size: 1.1rem;
|
||
font-weight: bold;
|
||
color: #856404;
|
||
margin-bottom: 15px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.joker-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 15px;
|
||
}
|
||
|
||
.joker-player {
|
||
background: white;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 6px;
|
||
padding: 15px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.joker-player.used {
|
||
opacity: 0.6;
|
||
background: #f8f9fa;
|
||
}
|
||
|
||
.joker-checkbox {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.joker-checkbox:disabled {
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* Action Buttons */
|
||
.action-buttons {
|
||
display: flex;
|
||
gap: 15px;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.action-btn {
|
||
background: #007bff;
|
||
border: none;
|
||
color: white;
|
||
padding: 15px 30px;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-size: 1.1rem;
|
||
font-weight: bold;
|
||
transition: all 0.2s ease;
|
||
min-width: 200px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.action-btn:hover {
|
||
background: #0056b3;
|
||
transform: translateY(-1px);
|
||
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
|
||
}
|
||
|
||
.action-btn:disabled {
|
||
background: #6c757d;
|
||
cursor: not-allowed;
|
||
transform: none;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.action-btn.success {
|
||
background: #28a745;
|
||
}
|
||
|
||
.action-btn.success:hover {
|
||
background: #1e7e34;
|
||
}
|
||
|
||
.action-btn.danger {
|
||
background: #dc3545;
|
||
}
|
||
|
||
.action-btn.danger:hover {
|
||
background: #c82333;
|
||
}
|
||
|
||
.player-count {
|
||
margin: 20px 0;
|
||
font-size: 1.2rem;
|
||
color: #333;
|
||
text-align: center;
|
||
}
|
||
|
||
.enabled-count {
|
||
color: #28a745;
|
||
font-weight: bold;
|
||
font-size: 1.4rem;
|
||
}
|
||
|
||
.warning {
|
||
background: #fff3cd;
|
||
border: 1px solid #ffeaa7;
|
||
color: #856404;
|
||
padding: 12px 16px;
|
||
border-radius: 6px;
|
||
margin: 15px 0;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* Tournament Status */
|
||
.tournament-status {
|
||
text-align: center;
|
||
padding: 30px;
|
||
}
|
||
|
||
.tournament-active {
|
||
color: #28a745;
|
||
font-size: 1.4rem;
|
||
font-weight: bold;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.tournament-inactive {
|
||
color: #6c757d;
|
||
font-size: 1.2rem;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.tournament-info {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 15px;
|
||
}
|
||
|
||
/* Add Player Form */
|
||
.add-player-form {
|
||
display: flex;
|
||
gap: 15px;
|
||
align-items: center;
|
||
padding: 20px;
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
margin-bottom: 25px;
|
||
}
|
||
|
||
.add-player-form input {
|
||
flex: 1;
|
||
padding: 12px 15px;
|
||
border: 1px solid #ced4da;
|
||
border-radius: 6px;
|
||
font-size: 1rem;
|
||
transition: border-color 0.2s ease;
|
||
}
|
||
|
||
.add-player-form input:focus {
|
||
outline: none;
|
||
border-color: #007bff;
|
||
}
|
||
|
||
.add-btn {
|
||
background: #28a745;
|
||
border: none;
|
||
color: white;
|
||
padding: 12px 20px;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
font-size: 1rem;
|
||
transition: background-color 0.2s ease;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.add-btn:hover {
|
||
background: #218838;
|
||
}
|
||
|
||
.add-btn:disabled {
|
||
background: #6c757d;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.uncheck-all-btn {
|
||
background: #dc3545;
|
||
border: none;
|
||
color: white;
|
||
padding: 12px 20px;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
font-size: 1rem;
|
||
transition: background-color 0.2s ease;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.uncheck-all-btn:hover {
|
||
background: #c82333;
|
||
}
|
||
|
||
.uncheck-all-btn:disabled {
|
||
background: #6c757d;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* Player Cards */
|
||
.player-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||
gap: 20px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.player-card {
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||
border: 1px solid #dee2e6;
|
||
transition: box-shadow 0.2s ease;
|
||
position: relative;
|
||
}
|
||
|
||
.player-card.competing {
|
||
border-color: #28a745;
|
||
background: #f8fff9;
|
||
}
|
||
|
||
.player-card.not-competing {
|
||
border-color: #dc3545;
|
||
background: #fff5f5;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.player-card:hover {
|
||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.player-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.player-id-badge {
|
||
background: #007bff;
|
||
color: white;
|
||
padding: 6px 12px;
|
||
border-radius: 15px;
|
||
font-size: 0.9rem;
|
||
font-weight: bold;
|
||
min-width: 40px;
|
||
text-align: center;
|
||
}
|
||
|
||
.player-status {
|
||
font-size: 0.9rem;
|
||
font-weight: bold;
|
||
padding: 4px 10px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.status-competing {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
}
|
||
|
||
.status-not-competing {
|
||
background: #f8d7da;
|
||
color: #721c24;
|
||
}
|
||
|
||
.player-name-section {
|
||
margin: 15px 0;
|
||
}
|
||
|
||
.player-name {
|
||
font-size: 1.2rem;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.player-name input {
|
||
width: 100%;
|
||
padding: 8px 12px;
|
||
border: 1px solid #ced4da;
|
||
border-radius: 6px;
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
background: white;
|
||
transition: border-color 0.2s ease;
|
||
}
|
||
|
||
.player-name input:focus {
|
||
outline: none;
|
||
border-color: #007bff;
|
||
}
|
||
|
||
.player-controls {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 15px;
|
||
margin-top: 20px;
|
||
padding-top: 15px;
|
||
border-top: 1px solid #e9ecef;
|
||
}
|
||
|
||
.competing-toggle {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
cursor: pointer;
|
||
padding: 5px 10px;
|
||
border-radius: 6px;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
|
||
.competing-toggle:hover {
|
||
background: #f8f9fa;
|
||
}
|
||
|
||
.toggle-checkbox {
|
||
width: 18px;
|
||
height: 18px;
|
||
cursor: pointer;
|
||
accent-color: #28a745;
|
||
}
|
||
|
||
.toggle-label {
|
||
font-weight: 500;
|
||
color: #333;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.card-buttons {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.edit-btn {
|
||
background: #ffc107;
|
||
border: none;
|
||
color: white;
|
||
padding: 6px 12px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
|
||
.edit-btn:hover {
|
||
background: #e0a800;
|
||
}
|
||
|
||
.delete-btn {
|
||
background: #dc3545;
|
||
border: none;
|
||
color: white;
|
||
padding: 6px 12px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
|
||
.delete-btn:hover {
|
||
background: #c82333;
|
||
}
|
||
|
||
/* Confirmation Modal */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.modal-overlay.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
.confirmation-modal {
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 25px;
|
||
max-width: 500px;
|
||
width: 90%;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||
transform: scale(0.9);
|
||
transition: transform 0.2s ease;
|
||
}
|
||
|
||
.modal-overlay.active .confirmation-modal {
|
||
transform: scale(1);
|
||
}
|
||
|
||
.modal-title {
|
||
font-size: 1.2rem;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.modal-message {
|
||
color: #666;
|
||
margin-bottom: 20px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.modal-buttons {
|
||
display: flex;
|
||
gap: 12px;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.modal-btn {
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-weight: 500;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
|
||
.modal-btn.cancel {
|
||
background: #6c757d;
|
||
color: white;
|
||
}
|
||
|
||
.modal-btn.cancel:hover {
|
||
background: #5a6268;
|
||
}
|
||
|
||
.modal-btn.confirm {
|
||
background: #dc3545;
|
||
color: white;
|
||
}
|
||
|
||
.modal-btn.confirm:hover {
|
||
background: #c82333;
|
||
}
|
||
|
||
/* Mobile responsive */
|
||
@media (max-width: 768px) {
|
||
.navbar {
|
||
padding: 12px 20px;
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
}
|
||
|
||
.navbar-controls {
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
}
|
||
|
||
.container {
|
||
padding: 20px 15px;
|
||
}
|
||
|
||
.player-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.add-player-form {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
gap: 12px;
|
||
}
|
||
|
||
.tournament-info, .league-info {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.type-options {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.action-buttons {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.action-btn {
|
||
min-width: 250px;
|
||
}
|
||
|
||
.player-controls {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
gap: 10px;
|
||
}
|
||
|
||
.card-buttons {
|
||
justify-content: center;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="navbar">
|
||
<div class="navbar-title">🏆 Tournament Management</div>
|
||
<div class="navbar-controls">
|
||
<a href="/" class="nav-btn">← Dashboard</a>
|
||
{% if league_state and not league_state.league_finished %}
|
||
<a href="/results/calculator" class="nav-btn primary">🎯 Results Calculator</a>
|
||
<button class="nav-btn danger" onclick="resetLeague()">🗑️ Reset League</button>
|
||
{% elif tournament_state %}
|
||
<a href="/tournament/draft" class="nav-btn">📋 View Draft</a>
|
||
<a href="/results/calculator" class="nav-btn primary">🎯 Results Calculator</a>
|
||
<button class="nav-btn danger" onclick="resetTournament()">🗑️ Reset Tournament</button>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<!-- League Status Section -->
|
||
<!-- League or Tournament Management Section -->
|
||
<div class="section">
|
||
{% if league_state and not league_state.league_finished %}
|
||
<h2 class="section-title">🏆 League Management</h2>
|
||
<div class="league-status">
|
||
<div class="league-active">🏆 League Active</div>
|
||
<div class="league-info">
|
||
<div class="info-item">
|
||
<div class="info-label">Tournament Type</div>
|
||
<div class="info-value">
|
||
{% if league_state.tournament_type == '40_targets' %}
|
||
40 Targets
|
||
{% else %}
|
||
20 Targets
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Current Tournament</div>
|
||
<div class="info-value">{{ league_state.current_tournament }} / {{ league_state.total_tournaments }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Participants</div>
|
||
<div class="info-value">{{ league_state.participants|length }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Completed</div>
|
||
<div class="info-value">{{ league_state.completed_tournaments|length }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Created</div>
|
||
<div class="info-value">{{ league_state.created_at[:10] }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
{% if tournament_state %}
|
||
{% else %}
|
||
{% if league_state.current_tournament < league_state.total_tournaments %}
|
||
<!-- Joker selection -->
|
||
<div class="joker-section" id="jokerSection">
|
||
<div class="joker-title">🃏 Joker Selection for Tournament {{ league_state.current_tournament + 1 }}</div>
|
||
<p style="margin-bottom: 15px; color: #856404;">Select players who will use their joker (skip this tournament). Each player can only use their joker once per league.</p>
|
||
|
||
<div class="joker-grid">
|
||
{% for player_id, participant in league_state.participants.items() %}
|
||
<div class="joker-player {% if participant.joker_used %}used{% endif %}">
|
||
<span>{{ participant.name }}</span>
|
||
<input type="checkbox"
|
||
class="joker-checkbox"
|
||
id="joker_{{ player_id }}"
|
||
{% if participant.joker_used %}disabled{% endif %}
|
||
data-player-id="{{ player_id }}">
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="action-buttons">
|
||
<button class="action-btn success" onclick="startNextTournament()">
|
||
🚀 Start Tournament {{ league_state.current_tournament + 1 }}
|
||
</button>
|
||
</div>
|
||
{% else %}
|
||
<div class="warning">
|
||
<strong>League Complete!</strong> All tournaments scheduled. Finish current one to see final results.
|
||
</div>
|
||
{% endif %}
|
||
{% endif %}
|
||
</div>
|
||
|
||
{% elif league_state and league_state.league_finished %}
|
||
<h2 class="section-title">🏁 League Completed</h2>
|
||
<div class="league-status">
|
||
<div class="league-active">🏆 League Completed!</div>
|
||
<div class="league-info">
|
||
<div class="info-item">
|
||
<div class="info-label">Tournament Type</div>
|
||
<div class="info-value">{{ league_state.tournament_type == '40_targets' and '40 Targets' or '20 Targets' }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Participants</div>
|
||
<div class="info-value">{{ league_state.participants|length }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Tournaments</div>
|
||
<div class="info-value">{{ league_state.total_tournaments }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Finished</div>
|
||
<div class="info-value">{{ league_state.finished_at[:10] if league_state.finished_at else 'Today' }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="action-buttons">
|
||
<a href="/results" class="action-btn success">🏆 View League Results</a>
|
||
<button class="action-btn danger" onclick="resetLeague()">🗑️ Reset League</button>
|
||
</div>
|
||
</div>
|
||
|
||
{% elif not league_state and tournament_state %}
|
||
<h2 class="section-title">🎯 Single Tournament Management</h2>
|
||
<div class="tournament-status">
|
||
<div class="tournament-active">🎯 Tournament Active</div>
|
||
<div class="league-info">
|
||
<div class="info-item">
|
||
<div class="info-label">Tournament Type</div>
|
||
<div class="info-value">{{ tournament_state.tournament_type == '40_targets' and '40 Targets' or '20 Targets' }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Players</div>
|
||
<div class="info-value">{{ tournament_state.total_players }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Rounds</div>
|
||
<div class="info-value">{{ tournament_state.total_rounds }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Current Round</div>
|
||
<div class="info-value">{{ tournament_state.current_round }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Created</div>
|
||
<div class="info-value">{{ tournament_state.created_at[:10] if tournament_state.created_at else 'Today' }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="action-buttons">
|
||
<a href="/tournament/draft" class="action-btn">📋 View Draft</a>
|
||
<a href="/results/calculator" class="action-btn success">🎯 Score Tournament</a>
|
||
<a href="/" class="action-btn">📺 Dashboard</a>
|
||
<button class="action-btn danger" onclick="resetTournament()">🗑️ Reset Tournament</button>
|
||
</div>
|
||
</div>
|
||
|
||
{% else %}
|
||
<h2 class="section-title">🏁 Setup</h2>
|
||
<div class="league-inactive">No Active League or Tournament</div>
|
||
|
||
<!-- Tournament Type Selection -->
|
||
<div class="tournament-type-selection">
|
||
<div class="type-title">🎯 Select Tournament Type</div>
|
||
<div class="type-options">
|
||
<div class="type-option selected" onclick="selectTournamentType('20_targets')">
|
||
<input type="radio" name="tournament_type" value="20_targets" checked>
|
||
<div class="type-name">20 Targets</div>
|
||
<div class="type-description">Standard format with 20 targets, 2 shots each (40 shots total)</div>
|
||
</div>
|
||
<div class="type-option" onclick="selectTournamentType('40_targets')">
|
||
<input type="radio" name="tournament_type" value="40_targets">
|
||
<div class="type-name">40 Targets</div>
|
||
<div class="type-description">Extended format with 40 targets, 2 shots each (80 shots total)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="player-count">
|
||
<span class="enabled-count" id="enabledCount">0</span> players enabled
|
||
</div>
|
||
|
||
<div class="action-buttons">
|
||
<button class="action-btn success" id="startLeagueBtn" onclick="startLeague()">🏆 Start League (6 Tournaments)</button>
|
||
<button class="action-btn" id="startSingleBtn" onclick="startSingleTournament()">🎯 Start Single Tournament</button>
|
||
</div>
|
||
|
||
<div class="warning" id="warningMessage" style="display: none;">
|
||
<strong>Note:</strong> You need at least 1 enabled player to start.
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
|
||
<!-- Current Tournament Status (if active) -->
|
||
{% if tournament_state and league_state %}
|
||
<div class="section">
|
||
<h2 class="section-title">📋 Current Tournament</h2>
|
||
|
||
<div class="tournament-status">
|
||
<div class="tournament-active">🎯 Tournament Active</div>
|
||
<div class="tournament-info">
|
||
<div class="info-item">
|
||
<div class="info-label">Tournament Type</div>
|
||
<div class="info-value">
|
||
{% if tournament_state.tournament_type == '40_targets' %}
|
||
40 Targets
|
||
{% else %}
|
||
20 Targets
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Total Players</div>
|
||
<div class="info-value">{{ tournament_state.total_players }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Total Rounds</div>
|
||
<div class="info-value">{{ tournament_state.total_rounds }}</div>
|
||
</div>
|
||
<div class="info-item">
|
||
<div class="info-label">Current Round</div>
|
||
<div class="info-value">{{ tournament_state.current_round }}</div>
|
||
</div>
|
||
{% if league_state %}
|
||
<div class="info-item">
|
||
<div class="info-label">League Tournament</div>
|
||
<div class="info-value">{{ tournament_state.league_tournament_number or 'N/A' }}</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="action-buttons">
|
||
<a href="/tournament/draft" class="action-btn">📋 View Draft</a>
|
||
<a href="/results/calculator" class="action-btn success">🎯 Score Tournament</a>
|
||
<a href="/" class="action-btn">📺 Dashboard</a>
|
||
<button class="action-btn danger" onclick="resetTournament()">🗑️ Reset Tournament</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- Player Management Section -->
|
||
{% if not league_state and not tournament_state %}
|
||
<div class="section">
|
||
<h2 class="section-title">👥 Player Management</h2>
|
||
|
||
<!-- Add Player Form -->
|
||
<div class="add-player-form">
|
||
<input type="text"
|
||
id="newPlayerName"
|
||
placeholder="Enter player name..."
|
||
maxlength="50"
|
||
onkeypress="handleAddPlayerKeypress(event)">
|
||
<button class="add-btn" id="addPlayerBtn" onclick="addPlayer()">
|
||
➕ Add Player
|
||
</button>
|
||
<button class="uncheck-all-btn" onclick="uncheckAllPlayers()">
|
||
❌ Uncheck All
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Player Grid -->
|
||
<div class="player-grid" id="playerGrid">
|
||
<!-- Players will be loaded here -->
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<!-- Confirmation Modal -->
|
||
<div class="modal-overlay" id="confirmationModal">
|
||
<div class="confirmation-modal">
|
||
<div class="modal-title" id="modalTitle">Confirm Action</div>
|
||
<div class="modal-message" id="modalMessage">Are you sure you want to proceed?</div>
|
||
<div class="modal-buttons">
|
||
<button class="modal-btn cancel" onclick="closeModal()">Cancel</button>
|
||
<button class="modal-btn confirm" id="confirmBtn" onclick="confirmAction()">Confirm</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
let players = {{ players|tojson }};
|
||
const leagueActive = {{ 'true' if league_state and not league_state.league_finished else 'false' }};
|
||
const tournamentActive = {{ 'true' if tournament_state else 'false' }};
|
||
let pendingAction = null;
|
||
let editingPlayer = null;
|
||
let selectedTournamentType = '20_targets';
|
||
|
||
// Tournament type selection
|
||
function selectTournamentType(type) {
|
||
selectedTournamentType = type;
|
||
|
||
// Update UI
|
||
document.querySelectorAll('.type-option').forEach(option => {
|
||
option.classList.remove('selected');
|
||
});
|
||
|
||
event.currentTarget.classList.add('selected');
|
||
|
||
// Update radio button
|
||
const radio = event.currentTarget.querySelector('input[type="radio"]');
|
||
if (radio) radio.checked = true;
|
||
}
|
||
|
||
// Render players grid
|
||
function renderPlayerGrid() {
|
||
const playerGrid = document.getElementById('playerGrid');
|
||
playerGrid.innerHTML = '';
|
||
|
||
const enabledCount = players.filter(p => p.enabled).length;
|
||
document.getElementById('enabledCount').textContent = enabledCount;
|
||
|
||
// Update button states
|
||
const startLeagueBtn = document.getElementById('startLeagueBtn');
|
||
const startSingleBtn = document.getElementById('startSingleBtn');
|
||
const warningMsg = document.getElementById('warningMessage');
|
||
|
||
if (startLeagueBtn && startSingleBtn && warningMsg) {
|
||
if (enabledCount < 1) {
|
||
startLeagueBtn.disabled = true;
|
||
startSingleBtn.disabled = true;
|
||
warningMsg.style.display = 'block';
|
||
} else {
|
||
startLeagueBtn.disabled = false;
|
||
startSingleBtn.disabled = false;
|
||
warningMsg.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
players.forEach(player => {
|
||
const card = document.createElement('div');
|
||
card.className = `player-card ${player.enabled ? 'competing' : 'not-competing'}`;
|
||
|
||
card.innerHTML = `
|
||
<div class="player-header">
|
||
<div class="player-id-badge">#${player.id}</div>
|
||
<div class="player-status ${player.enabled ? 'status-competing' : 'status-not-competing'}">
|
||
${player.enabled ? '✓ Competing' : '✗ Not Competing'}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="player-name-section">
|
||
<div class="player-name" id="playerName${player.id}">
|
||
${player.name}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="player-controls">
|
||
<div class="competing-toggle" onclick="togglePlayer(${player.id})">
|
||
<input type="checkbox" class="toggle-checkbox" ${player.enabled ? 'checked' : ''} onchange="togglePlayer(${player.id})">
|
||
<span class="toggle-label">Competing</span>
|
||
</div>
|
||
|
||
<div class="card-buttons">
|
||
<button class="edit-btn" onclick="editPlayer(${player.id})" title="Edit Player Name">
|
||
✏️ Edit
|
||
</button>
|
||
<button class="delete-btn" onclick="confirmDeletePlayer(${player.id})" title="Delete Player">
|
||
🗑️ Delete
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
playerGrid.appendChild(card);
|
||
});
|
||
}
|
||
|
||
// Add new player
|
||
async function addPlayer() {
|
||
const nameInput = document.getElementById('newPlayerName');
|
||
const name = nameInput.value.trim();
|
||
|
||
if (!name) {
|
||
alert('Please enter a player name');
|
||
return;
|
||
}
|
||
|
||
const addBtn = document.getElementById('addPlayerBtn');
|
||
addBtn.disabled = true;
|
||
addBtn.textContent = 'Adding...';
|
||
|
||
try {
|
||
const response = await fetch('/api/players/add', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ name: name })
|
||
});
|
||
|
||
if (response.ok) {
|
||
const result = await response.json();
|
||
players.push(result.player);
|
||
nameInput.value = '';
|
||
renderPlayerGrid();
|
||
} else {
|
||
const error = await response.json();
|
||
alert('Failed to add player: ' + error.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error adding player:', error);
|
||
alert('Error adding player. Please try again.');
|
||
} finally {
|
||
addBtn.disabled = false;
|
||
addBtn.textContent = '➕ Add Player';
|
||
}
|
||
}
|
||
|
||
// Handle Enter key in add player input
|
||
function handleAddPlayerKeypress(event) {
|
||
if (event.key === 'Enter') {
|
||
event.preventDefault();
|
||
addPlayer();
|
||
}
|
||
}
|
||
|
||
// Edit player name
|
||
function editPlayer(playerId) {
|
||
const player = players.find(p => p.id === playerId);
|
||
if (!player) return;
|
||
|
||
const nameElement = document.getElementById(`playerName${playerId}`);
|
||
if (editingPlayer === playerId) {
|
||
// Save changes
|
||
const input = nameElement.querySelector('input');
|
||
if (input) {
|
||
const newName = input.value.trim();
|
||
if (newName && newName !== player.name) {
|
||
updatePlayerName(playerId, newName);
|
||
} else {
|
||
editingPlayer = null;
|
||
renderPlayerGrid();
|
||
}
|
||
}
|
||
} else {
|
||
// Start editing
|
||
editingPlayer = playerId;
|
||
nameElement.innerHTML = `
|
||
<input type="text" value="${player.name}" maxlength="50"
|
||
onblur="savePlayerName(${playerId})"
|
||
onkeypress="handleEditKeypress(event, ${playerId})"
|
||
autofocus>
|
||
`;
|
||
}
|
||
}
|
||
|
||
function savePlayerName(playerId) {
|
||
editPlayer(playerId);
|
||
}
|
||
|
||
function handleEditKeypress(event, playerId) {
|
||
if (event.key === 'Enter') {
|
||
event.preventDefault();
|
||
editPlayer(playerId);
|
||
} else if (event.key === 'Escape') {
|
||
editingPlayer = null;
|
||
renderPlayerGrid();
|
||
}
|
||
}
|
||
|
||
// Update player name
|
||
async function updatePlayerName(playerId, newName) {
|
||
try {
|
||
const response = await fetch(`/api/players/${playerId}`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ name: newName.trim() })
|
||
});
|
||
|
||
if (response.ok) {
|
||
// Update local player data
|
||
const player = players.find(p => p.id === playerId);
|
||
if (player) {
|
||
player.name = newName.trim();
|
||
}
|
||
editingPlayer = null;
|
||
renderPlayerGrid();
|
||
} else {
|
||
alert('Failed to update player name');
|
||
editingPlayer = null;
|
||
renderPlayerGrid();
|
||
}
|
||
} catch (error) {
|
||
console.error('Error updating player:', error);
|
||
editingPlayer = null;
|
||
renderPlayerGrid();
|
||
}
|
||
}
|
||
|
||
// Toggle player enabled/disabled
|
||
async function togglePlayer(playerId) {
|
||
const player = players.find(p => p.id === playerId);
|
||
if (!player) return;
|
||
|
||
const newEnabled = !player.enabled;
|
||
|
||
try {
|
||
const response = await fetch(`/api/players/${playerId}`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ enabled: newEnabled })
|
||
});
|
||
|
||
if (response.ok) {
|
||
player.enabled = newEnabled;
|
||
renderPlayerGrid();
|
||
} else {
|
||
alert('Failed to update player status');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error toggling player:', error);
|
||
alert('Error updating player. Please try again.');
|
||
}
|
||
}
|
||
|
||
// Uncheck all players
|
||
async function uncheckAllPlayers() {
|
||
const competingPlayers = players.filter(p => p.enabled);
|
||
|
||
if (competingPlayers.length === 0) {
|
||
alert('No players are currently competing');
|
||
return;
|
||
}
|
||
|
||
if (!confirm(`Are you sure you want to uncheck all ${competingPlayers.length} competing players?`)) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Update each player that is currently enabled
|
||
for (const player of competingPlayers) {
|
||
const response = await fetch(`/api/players/${player.id}`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ enabled: false })
|
||
});
|
||
|
||
if (response.ok) {
|
||
player.enabled = false;
|
||
}
|
||
}
|
||
|
||
renderPlayerGrid();
|
||
} catch (error) {
|
||
console.error('Error unchecking players:', error);
|
||
alert('Error unchecking players. Please try again.');
|
||
}
|
||
}
|
||
|
||
// Confirm delete player
|
||
function confirmDeletePlayer(playerId) {
|
||
const player = players.find(p => p.id === playerId);
|
||
if (!player) return;
|
||
|
||
showModal(
|
||
'Delete Player',
|
||
`Are you sure you want to permanently delete "${player.name}"? This action cannot be undone.`,
|
||
() => deletePlayer(playerId)
|
||
);
|
||
}
|
||
|
||
// Delete player
|
||
async function deletePlayer(playerId) {
|
||
try {
|
||
const response = await fetch(`/api/players/${playerId}/delete`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
players = players.filter(p => p.id !== playerId);
|
||
renderPlayerGrid();
|
||
closeModal();
|
||
} else {
|
||
alert('Failed to delete player');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error deleting player:', error);
|
||
alert('Error deleting player. Please try again.');
|
||
}
|
||
}
|
||
|
||
// Start league
|
||
async function startLeague() {
|
||
const enabledPlayers = players.filter(p => p.enabled);
|
||
|
||
if (enabledPlayers.length < 1) {
|
||
alert('Need at least 1 enabled player to start league');
|
||
return;
|
||
}
|
||
|
||
if (!confirm(`Start league with ${enabledPlayers.length} players using ${selectedTournamentType === '40_targets' ? '40' : '20'} targets format?`)) {
|
||
return;
|
||
}
|
||
|
||
const startBtn = document.getElementById('startLeagueBtn');
|
||
startBtn.disabled = true;
|
||
startBtn.textContent = 'Starting League...';
|
||
|
||
try {
|
||
const response = await fetch('/api/league/start', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ tournament_type: selectedTournamentType })
|
||
});
|
||
|
||
if (response.ok) {
|
||
const result = await response.json();
|
||
alert('League started successfully!');
|
||
window.location.reload();
|
||
} else {
|
||
const error = await response.json();
|
||
alert('Failed to start league: ' + error.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error starting league:', error);
|
||
alert('Error starting league. Please try again.');
|
||
} finally {
|
||
startBtn.disabled = false;
|
||
startBtn.textContent = '🏆 Start League (6 Tournaments)';
|
||
}
|
||
}
|
||
|
||
// Start single tournament
|
||
async function startSingleTournament() {
|
||
const enabledPlayers = players.filter(p => p.enabled);
|
||
|
||
if (enabledPlayers.length < 1) {
|
||
alert('Need at least 1 enabled player to start tournament');
|
||
return;
|
||
}
|
||
|
||
if (!confirm(`Start single tournament with ${enabledPlayers.length} players using ${selectedTournamentType === '40_targets' ? '40' : '20'} targets format?`)) {
|
||
return;
|
||
}
|
||
|
||
const startBtn = document.getElementById('startSingleBtn');
|
||
startBtn.disabled = true;
|
||
startBtn.textContent = 'Starting...';
|
||
|
||
try {
|
||
const response = await fetch('/api/tournament/start', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ tournament_type: selectedTournamentType })
|
||
});
|
||
|
||
if (response.ok) {
|
||
const result = await response.json();
|
||
alert('Tournament started successfully!');
|
||
window.location.reload();
|
||
} else {
|
||
const error = await response.json();
|
||
alert('Failed to start tournament: ' + error.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error starting tournament:', error);
|
||
alert('Error starting tournament. Please try again.');
|
||
} finally {
|
||
startBtn.disabled = false;
|
||
startBtn.textContent = '🎯 Start Single Tournament';
|
||
}
|
||
}
|
||
|
||
// Start next tournament in league
|
||
async function startNextTournament() {
|
||
// Get selected joker players
|
||
const jokerCheckboxes = document.querySelectorAll('.joker-checkbox:checked:not(:disabled)');
|
||
const jokerPlayers = Array.from(jokerCheckboxes).map(cb => parseInt(cb.dataset.playerId));
|
||
|
||
if (!confirm(`Start next tournament? ${jokerPlayers.length} players will use their joker.`)) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('/api/league/tournament/start', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ joker_players: jokerPlayers })
|
||
});
|
||
|
||
if (response.ok) {
|
||
const result = await response.json();
|
||
alert('Tournament started successfully!');
|
||
window.location.reload();
|
||
} else {
|
||
const error = await response.json();
|
||
alert('Failed to start tournament: ' + error.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error starting tournament:', error);
|
||
alert('Error starting tournament. Please try again.');
|
||
}
|
||
}
|
||
|
||
// Reset league
|
||
async function resetLeague() {
|
||
if (!confirm('Are you sure you want to reset the league? This will delete all league and tournament data.')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('/api/league/reset', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('League reset successfully!');
|
||
window.location.reload();
|
||
} else {
|
||
alert('Failed to reset league');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error resetting league:', error);
|
||
alert('Error resetting league. Please try again.');
|
||
}
|
||
}
|
||
|
||
// Reset tournament
|
||
async function resetTournament() {
|
||
if (!confirm('Are you sure you want to reset the tournament? This will delete tournament data.')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('/api/tournament/reset', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('Tournament reset successfully!');
|
||
window.location.reload();
|
||
} else {
|
||
alert('Failed to reset tournament');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error resetting tournament:', error);
|
||
alert('Error resetting tournament. Please try again.');
|
||
}
|
||
}
|
||
|
||
// Modal functions
|
||
function showModal(title, message, confirmCallback) {
|
||
document.getElementById('modalTitle').textContent = title;
|
||
document.getElementById('modalMessage').textContent = message;
|
||
pendingAction = confirmCallback;
|
||
document.getElementById('confirmationModal').classList.add('active');
|
||
}
|
||
|
||
function closeModal() {
|
||
document.getElementById('confirmationModal').classList.remove('active');
|
||
pendingAction = null;
|
||
}
|
||
|
||
function confirmAction() {
|
||
if (pendingAction) {
|
||
pendingAction();
|
||
}
|
||
}
|
||
|
||
// Click outside modal to close
|
||
document.getElementById('confirmationModal').addEventListener('click', function(e) {
|
||
if (e.target === this) {
|
||
closeModal();
|
||
}
|
||
});
|
||
|
||
// Initialize page
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
renderPlayerGrid();
|
||
|
||
// Focus on add player input if no active league/tournament
|
||
const nameInput = document.getElementById('newPlayerName');
|
||
if (nameInput && !leagueActive && !tournamentActive) {
|
||
nameInput.focus();
|
||
}
|
||
|
||
console.log('🏆 Tournament Management loaded');
|
||
console.log('League active:', leagueActive);
|
||
console.log('Tournament active:', tournamentActive);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |