ajouté dark mode et changer l'affichage des équipes dans les match. Changé les couleurs pour ressembler plus au couleur de l'udes

This commit is contained in:
cedrick2711
2026-07-14 23:34:56 -04:00
parent b19d5db8db
commit 5a090c0872
20 changed files with 632 additions and 107 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+48 -1
View File
@@ -1,8 +1,9 @@
from flask import Blueprint, render_template, redirect, url_for, flash from flask import Blueprint, render_template, redirect, url_for, flash
from flask_login import login_required, current_user from flask_login import login_required, current_user
from extensions import db from extensions import db
from models import User, Tryout, Evaluation, TryoutRegistration, Team, TeamMember from models import User, Tryout, Evaluation, TryoutRegistration, Team, TeamMember, Match, MatchParticipant
from sqlalchemy import func from sqlalchemy import func
from datetime import datetime, date
main_bp = Blueprint('main', __name__) main_bp = Blueprint('main', __name__)
@@ -48,6 +49,52 @@ def dashboard():
stats['my_registrations'] = TryoutRegistration.query.filter_by(player_id=user.id).order_by(TryoutRegistration.registered_at.desc()).limit(5).all() stats['my_registrations'] = TryoutRegistration.query.filter_by(player_id=user.id).order_by(TryoutRegistration.registered_at.desc()).limit(5).all()
stats['my_eval_list'] = Evaluation.query.filter_by(player_id=user.id).order_by(Evaluation.created_at.desc()).limit(5).all() stats['my_eval_list'] = Evaluation.query.filter_by(player_id=user.id).order_by(Evaluation.created_at.desc()).limit(5).all()
# Get next match for each tryout the player is in
today = date.today()
next_matches = []
for reg in stats['my_registrations']:
tryout = reg.tryout
# Find matches where player participates (team membership or direct participant)
player_teams = Team.query.join(TeamMember).filter(
Team.tryout_id == tryout.id,
TeamMember.player_id == user.id
).all()
# Get matches for this tryout that include the player
tryout_matches = Match.query.filter(
Match.tryout_id == tryout.id,
Match.status == 'scheduled'
).order_by(Match.date, Match.start_time).all()
for match in tryout_matches:
# Check if player is in this match
is_participant = False
if match.match_type == 'team_vs_team':
# Check if player is on team1 or team2
if match.team1_id in [t.id for t in player_teams] or match.team2_id in [t.id for t in player_teams]:
is_participant = True
else:
# Check if player is in match participants
participant = MatchParticipant.query.filter_by(
match_id=match.id,
player_id=user.id
).first()
if participant:
is_participant = True
if is_participant:
# Check if match is upcoming
match_date = match.date
if match_date >= today:
next_matches.append({
'tryout': tryout,
'match': match,
'team': player_teams[0] if player_teams else None
})
break # Only get the next match per tryout
stats['next_matches'] = next_matches
elif user.role == 'scout': elif user.role == 'scout':
stats['total_players'] = User.query.filter_by(role='player').count() stats['total_players'] = User.query.filter_by(role='player').count()
stats['total_evaluations'] = Evaluation.query.count() stats['total_evaluations'] = Evaluation.query.count()
+2 -2
View File
@@ -73,7 +73,7 @@ def api_events():
events.append({ events.append({
'id': f'match_{match.id}', 'id': f'match_{match.id}',
'title': match.title + ' (' + participants_str + ')', 'title': match.title,
'date': match.date.strftime('%Y-%m-%d'), 'date': match.date.strftime('%Y-%m-%d'),
'type': 'match', 'type': 'match',
'color': match_color, 'color': match_color,
@@ -181,7 +181,7 @@ def api_events_for_tryout(tryout_id):
events.append({ events.append({
'id': f'match_{match.id}', 'id': f'match_{match.id}',
'title': match.title + ' (' + participants_str + ')', 'title': match.title,
'date': match.date.strftime('%Y-%m-%d'), 'date': match.date.strftime('%Y-%m-%d'),
'type': 'match', 'type': 'match',
'color': match_color, 'color': match_color,
+6 -6
View File
@@ -172,13 +172,13 @@ def view_tryout(tryout_id):
'team2_players': [{'name': m.player.full_name, 'position': m.position} for m in match.team2.members.all()] if match.team2 else [] 'team2_players': [{'name': m.player.full_name, 'position': m.position} for m in match.team2.members.all()] if match.team2 else []
} }
elif match.match_type == 'player_vs_player': elif match.match_type == 'player_vs_player':
team1_players = [p.player.full_name for p in match.participants.filter_by(team_side=1).all()] team1_players = [{'name': p.player.full_name, 'position': p.position} for p in match.participants.filter_by(team_side=1).all() if p.player]
team2_players = [p.player.full_name for p in match.participants.filter_by(team_side=2).all()] team2_players = [{'name': p.player.full_name, 'position': p.position} for p in match.participants.filter_by(team_side=2).all() if p.player]
participants = { participants = {
'team1': ', '.join(team1_players) if team1_players else 'TBD', 'team1': 'Team 1',
'team2': ', '.join(team2_players) if team2_players else 'TBD', 'team2': 'Team 2',
'team1_player_names': team1_players, 'team1_players': team1_players,
'team2_player_names': team2_players 'team2_players': team2_players
} }
else: else:
participants = [p.player.full_name for p in match.participants.all()] participants = [p.player.full_name for p in match.participants.all()]
+360 -22
View File
@@ -1,28 +1,29 @@
:root { :root {
--primary: #4f46e5; /* New Color Palette */
--primary-dark: #4338ca; --primary: #00984C;
--primary-light: #eef2ff; --primary-dark: #003E21;
--success: #10b981; --primary-light: #E5A939;
--success-light: #ecfdf5; --success: #00984C;
--warning: #f59e0b; --success-light: #F0F2F2;
--warning-light: #fffbeb; --warning: #E5A939;
--warning-light: #FEF9F0;
--danger: #ef4444; --danger: #ef4444;
--danger-light: #fef2f2; --danger-light: #fef2f2;
--info: #3b82f6; --info: #3b82f6;
--info-light: #eff6ff; --info-light: #eff6ff;
--secondary: #6b7280; --secondary: #6b7280;
--secondary-light: #f3f4f6; --secondary-light: #F0F2F2;
--dark: #1f2937; --dark: #12130F;
--gray-50: #f9fafb; --gray-50: #F0F2F2;
--gray-100: #f3f4f6; --gray-100: #E8EAEB;
--gray-200: #e5e7eb; --gray-200: #D1D5DB;
--gray-300: #d1d5db; --gray-300: #9CA3AF;
--gray-400: #9ca3af; --gray-400: #6B7280;
--gray-500: #6b7280; --gray-500: #4B5563;
--gray-600: #4b5563; --gray-600: #374151;
--gray-700: #374151; --gray-700: #1F2937;
--gray-800: #1f2937; --gray-800: #12130F;
--gray-900: #111827; --gray-900: #0A0B0A;
--sidebar-width: 260px; --sidebar-width: 260px;
--sidebar-collapsed: 0px; --sidebar-collapsed: 0px;
--radius: 12px; --radius: 12px;
@@ -33,6 +34,26 @@
--transition: all 0.2s ease; --transition: all 0.2s ease;
} }
/* Dark Mode Variables */
[data-theme="dark"] {
--bg-primary: #12130F;
--bg-secondary: #1A1D17;
--bg-tertiary: #232820;
--text-primary: #F0F2F2;
--text-secondary: #D1D5DB;
--text-muted: #9CA3AF;
--border-color: #2D342A;
--card-bg: #1A1D17;
--sidebar-bg: #0A0B0A;
--sidebar-text: #F0F2F2;
--sidebar-hover: rgba(240, 242, 242, 0.08);
--input-bg: #232820;
--input-border: #2D342A;
--shadow: 0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2);
--shadow-md: 0 4px 6px rgba(0,0,0,0.25), 0 2px 4px rgba(0,0,0,0.2);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.3), 0 4px 6px rgba(0,0,0,0.2);
}
* { margin: 0; padding: 0; box-sizing: border-box; } * { margin: 0; padding: 0; box-sizing: border-box; }
body { body {
@@ -462,7 +483,7 @@ a:hover { color: var(--primary-dark); }
.form-group textarea:focus { .form-group textarea:focus {
outline: none; outline: none;
border-color: var(--primary); border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(79,70,229,0.1); box-shadow: 0 0 0 3px rgba(0, 152, 76, 0.1);
} }
.form-group textarea { resize: vertical; min-height: 80px; } .form-group textarea { resize: vertical; min-height: 80px; }
@@ -533,10 +554,14 @@ a:hover { color: var(--primary-dark); }
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #00984C 0%, #003E21 100%);
padding: 20px; padding: 20px;
} }
[data-theme="dark"] .auth-wrapper {
background: linear-gradient(135deg, #003E21 0%, #12130F 100%);
}
.auth-wrapper .flash-messages { .auth-wrapper .flash-messages {
width: 100%; width: 100%;
max-width: 420px; max-width: 420px;
@@ -606,7 +631,7 @@ a:hover { color: var(--primary-dark); }
.auth-form .form-group input:focus { .auth-form .form-group input:focus {
border-color: var(--primary); border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(79,70,229,0.1); box-shadow: 0 0 0 3px rgba(0, 152, 76, 0.1);
outline: none; outline: none;
} }
@@ -989,6 +1014,49 @@ a:hover { color: var(--primary-dark); }
color: var(--gray-600); color: var(--gray-600);
} }
/* Match Teams Display */
.match-teams {
display: flex;
align-items: flex-start;
gap: 12px;
}
.match-team {
flex: 1;
min-width: 0;
}
.match-team .team-name {
font-weight: 600;
color: var(--gray-800);
font-size: 0.9rem;
margin-bottom: 4px;
display: block;
}
.match-vs {
font-weight: 700;
color: var(--primary);
font-size: 0.85rem;
padding: 0 4px;
margin-top: 2px;
}
.team-players-list {
list-style: none;
padding: 0;
margin: 0;
font-size: 0.85rem;
}
.team-players-list li {
padding: 2px 0;
color: var(--gray-600);
display: flex;
align-items: center;
gap: 6px;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.sidebar { .sidebar {
width: var(--sidebar-collapsed); width: var(--sidebar-collapsed);
@@ -1161,3 +1229,273 @@ a:hover { color: var(--primary-dark); }
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 500; font-weight: 500;
} }
/* Dark Mode Styles */
[data-theme="dark"] body {
background: var(--bg-primary);
color: var(--text-primary);
}
[data-theme="dark"] .sidebar {
background: var(--sidebar-bg);
border-right: 1px solid var(--border-color);
}
[data-theme="dark"] .sidebar-header {
border-bottom: 1px solid var(--border-color);
}
[data-theme="dark"] .user-badge {
background: rgba(240, 242, 242, 0.05);
}
[data-theme="dark"] .nav-links li a {
color: var(--text-muted);
}
[data-theme="dark"] .nav-links li a:hover,
[data-theme="dark"] .nav-links li a.active {
background: var(--sidebar-hover);
color: var(--sidebar-text);
}
[data-theme="dark"] .nav-divider {
background: var(--border-color);
}
[data-theme="dark"] .top-bar {
background: var(--bg-secondary);
border-bottom: 1px solid var(--border-color);
}
[data-theme="dark"] .page-header h1 {
color: var(--text-primary);
}
[data-theme="dark"] .content {
background: var(--bg-primary);
}
[data-theme="dark"] .card {
background: var(--card-bg);
box-shadow: var(--shadow);
}
[data-theme="dark"] .card-header {
border-bottom: 1px solid var(--border-color);
}
[data-theme="dark"] .stat-card,
[data-theme="dark"] .team-card {
background: var(--card-bg);
}
[data-theme="dark"] .stat-info h3,
[data-theme="dark"] .team-name,
[data-theme="dark"] .detail-value {
color: var(--text-primary);
}
[data-theme="dark"] .stat-info p,
[data-theme="dark"] .detail-label,
[data-theme="dark"] .team-members li,
[data-theme="dark"] .team-members-list li,
[data-theme="dark"] .team-roster-display,
[data-theme="dark"] .form-text,
[data-theme="dark"] .time-selection-hint,
[data-theme="dark"] .randomize-preview {
color: var(--text-secondary);
}
[data-theme="dark"] .stat-item {
background: var(--bg-tertiary);
}
[data-theme="dark"] .table th {
color: var(--text-secondary);
border-bottom: 2px solid var(--border-color);
}
[data-theme="dark"] .table td {
border-bottom: 1px solid var(--border-color);
}
[data-theme="dark"] .table tbody tr:hover {
background: var(--bg-tertiary);
}
[data-theme="dark"] .form-group label {
color: var(--text-secondary);
}
[data-theme="dark"] .form-group input,
[data-theme="dark"] .form-group select,
[data-theme="dark"] .form-group textarea,
[data-theme="dark"] .form-select,
[data-theme="dark"] .form-input,
[data-theme="dark"] .randomize-input {
background: var(--input-bg);
border-color: var(--input-border);
color: var(--text-primary);
}
[data-theme="dark"] .form-group input::placeholder,
[data-theme="dark"] .form-group textarea::placeholder {
color: var(--text-muted);
}
[data-theme="dark"] .form-group input:focus,
[data-theme="dark"] .form-group select:focus,
[data-theme="dark"] .form-group textarea:focus {
box-shadow: 0 0 0 3px rgba(0, 152, 76, 0.2);
}
[data-theme="dark"] .form-actions {
border-top: 1px solid var(--border-color);
}
[data-theme="dark"] .modal-content {
background: var(--card-bg);
}
[data-theme="dark"] .modal-header {
border-bottom: 1px solid var(--border-color);
}
[data-theme="dark"] .modal-close {
color: var(--text-muted);
}
[data-theme="dark"] .modal-close:hover {
color: var(--text-primary);
}
[data-theme="dark"] .checkbox-label {
background: var(--bg-tertiary);
border-color: var(--border-color);
color: var(--text-secondary);
}
[data-theme="dark"] .checkbox-label:hover {
background: var(--bg-secondary);
}
[data-theme="dark"] .section-divider {
border-top: 1px solid var(--border-color);
}
[data-theme="dark"] .section-title,
[data-theme="dark"] .empty-state h3 {
color: var(--text-primary);
}
[data-theme="dark"] .empty-state i,
[data-theme="dark"] .empty-state p {
color: var(--text-muted);
}
[data-theme="dark"] .auth-container {
background: var(--card-bg);
}
[data-theme="dark"] .auth-header h2 {
color: var(--text-primary);
}
[data-theme="dark"] .auth-header p,
[data-theme="dark"] .auth-link {
color: var(--text-secondary);
}
[data-theme="dark"] .auth-form .form-group label {
color: var(--text-secondary);
}
[data-theme="dark"] .auth-form .form-group label i {
color: var(--text-muted);
}
[data-theme="dark"] .auth-form .form-group input {
background: var(--input-bg);
border-color: var(--input-border);
color: var(--text-primary);
}
[data-theme="dark"] .auth-form .form-group input:focus {
box-shadow: 0 0 0 3px rgba(0, 152, 76, 0.2);
}
[data-theme="dark"] .position-tag {
background: var(--bg-tertiary);
color: var(--primary);
}
[data-theme="dark"] .match-team .team-name {
color: var(--text-primary);
}
[data-theme="dark"] .merged-disponibility-time-block {
background: var(--bg-tertiary);
border-color: var(--border-color);
color: var(--text-secondary);
}
[data-theme="dark"] .merged-disponibility-time-block:hover {
background: var(--bg-secondary);
}
[data-theme="dark"] .merged-disponibility-selected-display {
background: var(--bg-tertiary);
}
[data-theme="dark"] .randomize-section {
background: var(--bg-tertiary);
}
[data-theme="dark"] .btn-secondary {
background: var(--bg-tertiary);
color: var(--text-secondary);
}
[data-theme="dark"] .btn-secondary:hover {
background: var(--bg-secondary);
}
[data-theme="dark"] .btn-outline {
background: transparent;
border-color: var(--border-color);
color: var(--text-secondary);
}
[data-theme="dark"] .btn-outline:hover {
background: var(--bg-tertiary);
}
/* Dark Mode Toggle Button */
.dark-mode-toggle {
background: none;
border: none;
font-size: 1.1rem;
color: var(--gray-500);
cursor: pointer;
padding: 6px 10px;
border-radius: var(--radius-sm);
display: flex;
align-items: center;
gap: 6px;
transition: var(--transition);
}
.dark-mode-toggle:hover {
background: var(--gray-100);
color: var(--gray-700);
}
[data-theme="dark"] .dark-mode-toggle {
color: var(--text-secondary);
}
[data-theme="dark"] .dark-mode-toggle:hover {
background: var(--bg-tertiary);
color: var(--text-primary);
}
+33
View File
@@ -1,3 +1,33 @@
// Dark Mode Toggle
function toggleDarkMode() {
const body = document.documentElement;
const isDark = body.getAttribute('data-theme') === 'dark';
const toggle = document.getElementById('darkModeToggle');
if (isDark) {
body.removeAttribute('data-theme');
localStorage.setItem('theme', 'light');
toggle.innerHTML = '<i class="fas fa-moon"></i>';
} else {
body.setAttribute('data-theme', 'dark');
localStorage.setItem('theme', 'dark');
toggle.innerHTML = '<i class="fas fa-sun"></i>';
}
}
// Load saved theme preference
function loadTheme() {
const savedTheme = localStorage.getItem('theme');
const toggle = document.getElementById('darkModeToggle');
if (savedTheme === 'dark') {
document.documentElement.setAttribute('data-theme', 'dark');
if (toggle) {
toggle.innerHTML = '<i class="fas fa-sun"></i>';
}
}
}
// Sidebar toggle for mobile // Sidebar toggle for mobile
function toggleSidebar() { function toggleSidebar() {
const sidebar = document.getElementById('sidebar'); const sidebar = document.getElementById('sidebar');
@@ -17,6 +47,9 @@ document.addEventListener('click', function(event) {
// Auto-dismiss flash messages // Auto-dismiss flash messages
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Load theme preference
loadTheme();
const alerts = document.querySelectorAll('.alert-dismissible'); const alerts = document.querySelectorAll('.alert-dismissible');
alerts.forEach(function(alert) { alerts.forEach(function(alert) {
setTimeout(function() { setTimeout(function() {
+3
View File
@@ -92,6 +92,9 @@
<h1>{% block page_title %}Dashboard{% endblock %}</h1> <h1>{% block page_title %}Dashboard{% endblock %}</h1>
{% block breadcrumb %}{% endblock %} {% block breadcrumb %}{% endblock %}
</div> </div>
<button class="dark-mode-toggle" id="darkModeToggle" onclick="toggleDarkMode()" title="Toggle dark mode">
<i class="fas fa-moon"></i>
</button>
{% block header_actions %}{% endblock %} {% block header_actions %}{% endblock %}
</header> </header>
<div class="flash-messages"> <div class="flash-messages">
+41 -4
View File
@@ -59,7 +59,7 @@
<link href="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js"></script>
<script> <script>
var canScheduleMatches = {{ 'true' if current_user.can_schedule_matches() else 'false' }}; var canScheduleMatches = {% if current_user.can_schedule_matches() %}true{% else %}false{% endif %};
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar'); var calendarEl = document.getElementById('calendar');
@@ -73,7 +73,9 @@ document.addEventListener('DOMContentLoaded', function() {
events: '/matches/api/events', events: '/matches/api/events',
eventClick: function(info) { eventClick: function(info) {
showEventModal(info.event); showEventModal(info.event);
} },
slotMinTime: '12:00:00',
slotMaxTime: '24:00:00'
}); });
calendar.render(); calendar.render();
@@ -95,8 +97,8 @@ function showEventModal(event) {
var content = '<div class="detail-grid">'; var content = '<div class="detail-grid">';
content += '<div class="detail-item"><span class="detail-label">Type</span><span class="detail-value">'; content += '<div class="detail-item"><span class="detail-label">Type</span><span class="detail-value">';
content += '<span class="badge badge-' + (type === 'tryout' ? 'info' : (props.match_type === 'team_vs_team' ? 'success' : 'warning')) + '">'; content += '<span class="badge badge-' + (type === 'tryout' ? 'info' : (props.match_type === 'team_vs_team' || props.match_type === 'player_vs_player' ? 'success' : 'warning')) + '">';
content += (type === 'tryout' ? 'Tryout' : (props.match_type === 'team_vs_team' ? 'Team Match' : 'Player Scrim')) + '</span>'; content += (type === 'tryout' ? 'Tryout' : (props.match_type === 'team_vs_team' ? 'Team Match' : (props.match_type === 'player_vs_player' ? 'Player Match' : 'Player Scrim'))) + '</span>';
content += '</span></div>'; content += '</span></div>';
content += '<div class="detail-item"><span class="detail-label">Title</span><span class="detail-value">' + title + '</span></div>'; content += '<div class="detail-item"><span class="detail-label">Title</span><span class="detail-value">' + title + '</span></div>';
content += '<div class="detail-item"><span class="detail-label">Date</span><span class="detail-value">' + date + '</span></div>'; content += '<div class="detail-item"><span class="detail-label">Date</span><span class="detail-value">' + date + '</span></div>';
@@ -105,6 +107,41 @@ function showEventModal(event) {
content += '<span class="badge badge-' + (props.status || 'scheduled') + '">' + (props.status || 'scheduled') + '</span>'; content += '<span class="badge badge-' + (props.status || 'scheduled') + '">' + (props.status || 'scheduled') + '</span>';
content += '</span></div>'; content += '</span></div>';
// Add team separation for matches
if (type === 'match' && props.participants) {
content += '<div class="detail-item full-width"><span class="detail-label">Teams</span><span class="detail-value">';
if (props.match_type === 'team_vs_team') {
// For team vs team, participants is "Team1 vs Team2"
var teams = props.participants.split(' vs ');
if (teams.length >= 2) {
content += '<div class="match-teams">';
content += '<div class="match-team"><span class="team-name">' + teams[0] + '</span></div>';
content += '<div class="match-vs">vs</div>';
content += '<div class="match-team"><span class="team-name">' + teams[1] + '</span></div>';
content += '</div>';
} else {
content += props.participants;
}
} else if (props.match_type === 'player_vs_player') {
// For player vs player, we need to parse the participants
// The format is "player1, player2 vs player3, player4"
var parts = props.participants.split(' vs ');
if (parts.length >= 2) {
content += '<div class="match-teams">';
content += '<div class="match-team"><span class="team-name">Team 1</span><ul class="team-players-list"><li>' + parts[0].split(', ').join('</li><li>') + '</li></ul></div>';
content += '<div class="match-vs">vs</div>';
content += '<div class="match-team"><span class="team-name">Team 2</span><ul class="team-players-list"><li>' + parts[1].split(', ').join('</li><li>') + '</li></ul></div>';
content += '</div>';
} else {
content += props.participants;
}
} else {
// For player scrim, just show the list
content += props.participants;
}
content += '</span></div>';
}
if (props.description) { if (props.description) {
content += '<div class="detail-item full-width"><span class="detail-label">Description</span><span class="detail-value">' + props.description + '</span></div>'; content += '<div class="detail-item full-width"><span class="detail-label">Description</span><span class="detail-value">' + props.description + '</span></div>';
} }
+2 -2
View File
@@ -194,9 +194,9 @@
{% block scripts %} {% block scripts %}
<script> <script>
// Time slots from 5pm (17:00) to 12am (24:00) // Time slots from 12pm (12:00) to 12am (24:00)
var TIME_SLOTS = []; var TIME_SLOTS = [];
for (var h = 17; h <= 24; h++) { for (var h = 12; h <= 24; h++) {
for (var m = 0; m < 60; m += 30) { for (var m = 0; m < 60; m += 30) {
if (h === 24 && m > 0) continue; if (h === 24 && m > 0) continue;
var displayHour; var displayHour;
+37
View File
@@ -241,6 +241,43 @@
</div> </div>
</div> </div>
<div class="dashboard-grid"> <div class="dashboard-grid">
<div class="card">
<div class="card-header">
<h3><i class="fas fa-futbol"></i> My Next Matches</h3>
</div>
<div class="card-body">
{% if stats.next_matches %}
<table class="table">
<thead><tr><th>Tryout</th><th>Match</th><th>Date & Time</th><th>Opponent</th></tr></thead>
<tbody>
{% for item in stats.next_matches %}
<tr>
<td><a href="{{ url_for('tryouts.view_tryout', tryout_id=item.tryout.id) }}">{{ item.tryout.title }}</a></td>
<td>{{ item.match.title }}</td>
<td>
{{ item.match.date.strftime('%m/%d/%Y') }}
{% if item.match.start_time %} at {{ item.match.start_time.strftime('%I:%M %p') }}{% endif %}
</td>
<td>
{% if item.match.match_type == 'team_vs_team' and item.team %}
{% if item.match.team1_id == item.team.id %}
vs {{ item.match.team2.name if item.match.team2 else 'TBD' }}
{% else %}
vs {{ item.match.team1.name if item.match.team1 else 'TBD' }}
{% endif %}
{% else %}
-
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted">No upcoming matches yet.</p>
{% endif %}
</div>
</div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-clipboard-list"></i> My Registrations</h3> <h3><i class="fas fa-clipboard-list"></i> My Registrations</h3>
+4 -4
View File
@@ -112,7 +112,7 @@
<div class="team-rosters mt-3"> <div class="team-rosters mt-3">
{% if match.team1 %} {% if match.team1 %}
<div class="team-roster"> <div class="team-roster">
<h5>{{ match.team1.name }} Players</h5> <h5>{{ match.team1.name }}</h5>
<ul class="team-members-list"> <ul class="team-members-list">
{% for member in match.team1.members %} {% for member in match.team1.members %}
<li>{{ member.player.full_name if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}</li> <li>{{ member.player.full_name if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}</li>
@@ -124,7 +124,7 @@
{% endif %} {% endif %}
{% if match.team2 %} {% if match.team2 %}
<div class="team-roster"> <div class="team-roster">
<h5>{{ match.team2.name }} Players</h5> <h5>{{ match.team2.name }}</h5>
<ul class="team-members-list"> <ul class="team-members-list">
{% for member in match.team2.members %} {% for member in match.team2.members %}
<li>{{ member.player.full_name if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}</li> <li>{{ member.player.full_name if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}</li>
@@ -224,9 +224,9 @@
{% block scripts %} {% block scripts %}
<script> <script>
// Time slots from 5pm (17:00) to 12am (24:00) // Time slots from 12pm (12:00) to 12am (24:00)
var TIME_SLOTS = []; var TIME_SLOTS = [];
for (var h = 17; h <= 24; h++) { for (var h = 12; h <= 24; h++) {
for (var m = 0; m < 60; m += 30) { for (var m = 0; m < 60; m += 30) {
if (h === 24 && m > 0) continue; if (h === 24 && m > 0) continue;
var displayHour; var displayHour;
+42 -12
View File
@@ -290,23 +290,53 @@
<td>{{ m.date.strftime('%m/%d/%Y') }}</td> <td>{{ m.date.strftime('%m/%d/%Y') }}</td>
<td> <td>
{% if m.match_type == 'team_vs_team' %} {% if m.match_type == 'team_vs_team' %}
{{ participants.team1 }} vs {{ participants.team2 }} <div class="match-teams">
{% if participants.team1_players or participants.team2_players %} <div class="match-team">
<div class="team-roster-display mt-1"> <span class="team-name">{{ m.team1.name if m.team1 else 'Team 1' }}</span>
{% if participants.team1_players %} {% if participants.team1_players %}
<small><strong>{{ m.team1.name if m.team1 else 'Team 1' }}:</strong> <ul class="team-players-list">
{% for pl in participants.team1_players %}{{ pl.name }}{% if not loop.last %}, {% endif %}{% endfor %} {% for pl in participants.team1_players %}
</small><br> <li>{{ pl.name }}{% if pl.position %} <span class="position-tag">{{ pl.position }}</span>{% endif %}</li>
{% endif %} {% endfor %}
{% if participants.team2_players %} </ul>
<small><strong>{{ m.team2.name if m.team2 else 'Team 2' }}:</strong>
{% for pl in participants.team2_players %}{{ pl.name }}{% if not loop.last %}, {% endif %}{% endfor %}
</small>
{% endif %} {% endif %}
</div> </div>
<div class="match-vs">vs</div>
<div class="match-team">
<span class="team-name">{{ m.team2.name if m.team2 else 'Team 2' }}</span>
{% if participants.team2_players %}
<ul class="team-players-list">
{% for pl in participants.team2_players %}
<li>{{ pl.name }}{% if pl.position %} <span class="position-tag">{{ pl.position }}</span>{% endif %}</li>
{% endfor %}
</ul>
{% endif %} {% endif %}
</div>
</div>
{% elif m.match_type == 'player_vs_player' %} {% elif m.match_type == 'player_vs_player' %}
{{ participants.team1 }} vs {{ participants.team2 }} <div class="match-teams">
<div class="match-team">
<span class="team-name">Team 1</span>
{% if participants.team1_players %}
<ul class="team-players-list">
{% for pl in participants.team1_players %}
<li>{{ pl.name }}{% if pl.position %} <span class="position-tag">{{ pl.position }}</span>{% endif %}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="match-vs">vs</div>
<div class="match-team">
<span class="team-name">Team 2</span>
{% if participants.team2_players %}
<ul class="team-players-list">
{% for pl in participants.team2_players %}
<li>{{ pl.name }}{% if pl.position %} <span class="position-tag">{{ pl.position }}</span>{% endif %}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{% else %} {% else %}
{{ participants | join(', ') }} {{ participants | join(', ') }}
{% endif %} {% endif %}