changement de l'affichage des tryouts et des matchs

This commit is contained in:
cedrick2711
2026-07-22 22:19:58 -04:00
parent 346229778f
commit 5e909014f8
14 changed files with 573 additions and 326 deletions
Binary file not shown.
+2 -2
View File
@@ -88,7 +88,7 @@ def create_app():
response.headers['X-Content-Type-Options'] = 'nosniff' response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY' response.headers['X-Frame-Options'] = 'DENY'
response.headers['X-XSS-Protection'] = '1; mode=block' response.headers['X-XSS-Protection'] = '1; mode=block'
response.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com; font-src 'self' https://cdnjs.cloudflare.com; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none';" response.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net; font-src 'self' https://cdnjs.cloudflare.com; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none';"
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains' response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
return response return response
@@ -133,5 +133,5 @@ def create_app():
if __name__ == '__main__': if __name__ == '__main__':
app = create_app() app = create_app()
# Debug mode should only be enabled via environment variable for security # Debug mode should only be enabled via environment variable for security
debug_mode = os.environ.get('FLASK_DEBUG', 'false').lower() == 'true' debug_mode = os.getenv('FLASK_DEBUG', 'false').lower() == 'true'
app.run(debug=debug_mode, host='0.0.0.0', port=5000) app.run(debug=debug_mode, host='0.0.0.0', port=5000)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -21,7 +21,7 @@ def is_safe_url(url):
""" """
if not url: if not url:
return False return False
parsed = url_parse(url) parsed = urlparse(url)
# Allow relative URLs (no netloc) or same-origin URLs # Allow relative URLs (no netloc) or same-origin URLs
return not parsed.netloc or parsed.netloc == request.host return not parsed.netloc or parsed.netloc == request.host
+58 -5
View File
@@ -6,8 +6,9 @@ This module handles player evaluation creation, management, and viewing.
from flask import Blueprint, render_template, redirect, url_for, flash, request from flask import Blueprint, render_template, redirect, url_for, flash, request
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, GAME_POSITIONS from models import User, Tryout, Evaluation, TryoutRegistration, GAME_POSITIONS, OrgTeam
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm import aliased
evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations') evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations')
@@ -41,13 +42,55 @@ def list_evaluations():
Evaluators (coach/manager): Their given evaluations. Evaluators (coach/manager): Their given evaluations.
Players: Their received evaluations. Players: Their received evaluations.
Supports sorting by any column header via 'sort' and 'order' query parameters.
Returns: Returns:
Response: Rendered evaluations list template. Response: Rendered evaluations list template.
""" """
user = current_user user = current_user
# Get sort parameters
sort_column = request.args.get('sort', 'created_at')
sort_order = request.args.get('order', 'desc')
# Validate sort_order
if sort_order not in ('asc', 'desc'):
sort_order = 'desc'
# Map sort columns to SQLAlchemy expressions using aliased User models for relationship sorting
player_alias = aliased(User, name='eval_player')
evaluator_alias = aliased(User, name='eval_evaluator')
sort_map = {
'tryout': Tryout.title,
'player': player_alias.full_name,
'evaluator': evaluator_alias.full_name,
'mecanics_score': Evaluation.mecanics_score,
'cohesion_score': Evaluation.cohesion_score,
'communication_score': Evaluation.communication_score,
'gamesense_score': Evaluation.gamesense_score,
'versatility_score': Evaluation.versatility_score,
'discipline_score': Evaluation.discipline_score,
'analysis_score': Evaluation.analysis_score,
'sport_ethics_score': Evaluation.sport_ethics_score,
'mental_score': Evaluation.mental_score,
'overall_score': Evaluation.overall_score,
'position_recommendation': Evaluation.position_recommendation,
'created_at': Evaluation.created_at,
}
sort_expr = sort_map.get(sort_column, Evaluation.created_at)
if sort_order == 'asc':
sort_expr = sort_expr.asc()
else:
sort_expr = sort_expr.desc()
if user.role == 'president': if user.role == 'president':
evaluations = Evaluation.query.order_by(Evaluation.created_at.desc()).all() evaluations = Evaluation.query \
.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id) \
.outerjoin(player_alias, Evaluation.player_id == player_alias.id) \
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id) \
.order_by(sort_expr).all()
avg_scores = db.session.query( avg_scores = db.session.query(
Evaluation.player_id, Evaluation.player_id,
func.count(Evaluation.id).label('eval_count'), func.count(Evaluation.id).label('eval_count'),
@@ -60,13 +103,23 @@ def list_evaluations():
player_scores[p.id] = {'player': p, 'count': row.eval_count, 'avg': round(row.avg_score, 1) if row.avg_score else 0} player_scores[p.id] = {'player': p, 'count': row.eval_count, 'avg': round(row.avg_score, 1) if row.avg_score else 0}
elif user.can_evaluate(): elif user.can_evaluate():
evaluations = Evaluation.query.filter_by(evaluator_id=user.id).order_by(Evaluation.created_at.desc()).all() evaluations = Evaluation.query \
.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id) \
.outerjoin(player_alias, Evaluation.player_id == player_alias.id) \
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id) \
.filter(Evaluation.evaluator_id == user.id) \
.order_by(sort_expr).all()
player_scores = {} player_scores = {}
else: else:
evaluations = Evaluation.query.filter_by(player_id=user.id).order_by(Evaluation.created_at.desc()).all() evaluations = Evaluation.query \
.outerjoin(Tryout, Evaluation.tryout_id == Tryout.id) \
.outerjoin(player_alias, Evaluation.player_id == player_alias.id) \
.outerjoin(evaluator_alias, Evaluation.evaluator_id == evaluator_alias.id) \
.filter(Evaluation.player_id == user.id) \
.order_by(sort_expr).all()
player_scores = {} player_scores = {}
return render_template('pages/evaluations.html', evaluations=evaluations, player_scores=player_scores) return render_template('pages/evaluations.html', evaluations=evaluations, player_scores=player_scores, sort_column=sort_column, sort_order=sort_order)
@evaluations_bp.route('/<int:tryout_id>/<int:player_id>', methods=['GET', 'POST']) @evaluations_bp.route('/<int:tryout_id>/<int:player_id>', methods=['GET', 'POST'])
+5 -3
View File
@@ -30,7 +30,7 @@ def list_tryouts():
- President: All tryouts - President: All tryouts
- Manager: Only their created tryouts - Manager: Only their created tryouts
- Coach: Tryouts targeting their org team - Coach: Tryouts targeting their org team
- Player: Upcoming and in-progress tryouts - Player: Only tryouts they are registered for or participating in
Returns: Returns:
Response: Rendered tryouts list template. Response: Rendered tryouts list template.
@@ -47,7 +47,9 @@ def list_tryouts():
else: else:
tryouts = [] tryouts = []
elif current_user.role == 'player': elif current_user.role == 'player':
tryouts = Tryout.query.filter(Tryout.status.in_(['upcoming', 'in_progress'])).order_by(Tryout.date.desc()).all() # Players only see tryouts they are registered for or participating in matches
from routes.matches import get_visible_tryouts_for_user
tryouts = get_visible_tryouts_for_user()
else: else:
tryouts = Tryout.query.order_by(Tryout.date.desc()).all() tryouts = Tryout.query.order_by(Tryout.date.desc()).all()
return render_template('pages/tryouts.html', tryouts=tryouts, now=datetime.utcnow()) return render_template('pages/tryouts.html', tryouts=tryouts, now=datetime.utcnow())
@@ -254,7 +256,7 @@ def view_tryout(tryout_id):
all_players = User.query.filter_by(role='player').order_by(User.full_name).all() all_players = User.query.filter_by(role='player').order_by(User.full_name).all()
# Get matches for this tryout with participant info # Get matches for this tryout with participant info
matches = Match.query.filter_by(tryout_id=tryout_id).order_by(Match.date).all() matches = Match.query.filter_by(tryout_id=tryout_id).order_by(Match.date, Match.start_time).all()
match_data = [] match_data = []
for match in matches: for match in matches:
if match.match_type == 'team_vs_team': if match.match_type == 'team_vs_team':
+144
View File
@@ -1749,3 +1749,147 @@ a:hover { color: var(--primary-dark); }
transform: translateY(-50%); transform: translateY(-50%);
margin: 0; margin: 0;
} }
/* ===== Tryouts Grid (Card-based Layout) ===== */
.tryouts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
.tryout-card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
border: 1px solid var(--border-color, #e0e0e0);
}
.tryout-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.tryout-card .card-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
}
.tryout-title {
font-size: 1.1rem;
font-weight: 600;
margin: 0;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tryout-info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.info-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.85rem;
}
.info-icon {
width: 16px;
text-align: center;
color: var(--text-muted, #888);
flex-shrink: 0;
}
.info-label {
font-weight: 600;
color: var(--text-secondary, #555);
min-width: 50px;
}
.info-value {
color: var(--text-primary, #333);
flex: 1;
text-align: right;
}
.tryout-description {
font-size: 0.85rem;
color: var(--text-secondary, #555);
line-height: 1.4;
}
.tryout-description p {
margin: 0;
}
.tryout-card .card-footer {
display: flex;
gap: 8px;
padding: 12px 16px;
background: var(--bg-secondary, #f8f9fa);
border-top: 1px solid var(--border-color, #e0e0e0);
}
/* ===== Full-width Schedule Card ===== */
.tryout-schedule-card {
width: 100%;
}
/* ===== Dark mode adjustments ===== */
[data-theme="dark"] .tryout-card {
border-color: var(--border-color, #333);
}
[data-theme="dark"] .tryout-card .card-footer {
background: var(--bg-secondary, #2a2a2a);
border-top-color: var(--border-color, #333);
}
[data-theme="dark"] .info-label {
color: var(--text-secondary, #aaa);
}
/* Sortable Table Headers */
.sort-link {
display: inline-flex;
align-items: center;
gap: 4px;
color: var(--gray-500);
font-weight: 600;
text-decoration: none;
transition: var(--transition);
}
.sort-link:hover {
color: var(--gray-800);
}
.sort-link .fas {
font-size: 0.75rem;
}
.sort-inactive {
opacity: 0.3;
font-size: 0.75rem;
}
.sort-link:hover .sort-inactive {
opacity: 0.5;
}
[data-theme="dark"] .sort-link {
color: var(--text-secondary);
}
[data-theme="dark"] .sort-link:hover {
color: var(--text-primary);
}
+35 -18
View File
@@ -4,6 +4,23 @@
{% block breadcrumb %}<span class="breadcrumb">Home / Evaluations</span>{% endblock %} {% block breadcrumb %}<span class="breadcrumb">Home / Evaluations</span>{% endblock %}
{% block content %} {% block content %}
{% set sort_column = sort_column | default('created_at') %}
{% set sort_order = sort_order | default('desc') %}
{% macro sort_link(column, label) %}
<th>
{% set new_order = 'asc' if (sort_column == column and sort_order == 'desc') else 'desc' %}
<a href="{{ url_for('evaluations.list_evaluations', sort=column, order=new_order) }}" class="sort-link">
{{ label }}
{% if sort_column == column %}
<i class="fas fa-arrow-{{ 'up' if sort_order == 'asc' else 'down' }}"></i>
{% else %}
<i class="fas fa-arrows-alt-v sort-inactive"></i>
{% endif %}
</a>
</th>
{% endmacro %}
{% if current_user.role == 'president' and player_scores %} {% if current_user.role == 'president' and player_scores %}
<div class="stats-grid mb-4"> <div class="stats-grid mb-4">
{% for pid, data in player_scores.items() %} {% for pid, data in player_scores.items() %}
@@ -35,29 +52,29 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th>Tryout</th> {{ sort_link('tryout', 'Tryout') }}
<th>Player</th> {{ sort_link('player', 'Player') }}
<th>Evaluator</th> {{ sort_link('evaluator', 'Evaluator') }}
<th>Mecanics</th> {{ sort_link('mecanics_score', 'Mecanics') }}
<th>Cohesion</th> {{ sort_link('cohesion_score', 'Cohesion') }}
<th>Communication</th> {{ sort_link('communication_score', 'Communication') }}
<th>Gamesense</th> {{ sort_link('gamesense_score', 'Gamesense') }}
<th>Versatility</th> {{ sort_link('versatility_score', 'Versatility') }}
<th>Discipline</th> {{ sort_link('discipline_score', 'Discipline') }}
<th>Analysis</th> {{ sort_link('analysis_score', 'Analysis') }}
<th>Sport Ethics</th> {{ sort_link('sport_ethics_score', 'Sport Ethics') }}
<th>Mental</th> {{ sort_link('mental_score', 'Mental') }}
<th>Overall</th> {{ sort_link('overall_score', 'Overall') }}
<th>Position</th> {{ sort_link('position_recommendation', 'Position') }}
<th>Date</th> {{ sort_link('created_at', 'Date') }}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for eval in evaluations %} {% for eval in evaluations %}
<tr> <tr>
<td>{{ eval.tryout.title }}</td> <td>{{ eval.tryout.title if eval.tryout else 'Deleted Tryout' }}</td>
<td>{{ eval.player.full_name }}</td> <td>{{ eval.player.full_name if eval.player else 'Deleted Player' }}</td>
<td>{{ eval.evaluator.full_name }}</td> <td>{{ eval.evaluator.full_name if eval.evaluator else 'Deleted Evaluator' }}</td>
<td>{{ eval.mecanics_score or '-' }}</td> <td>{{ eval.mecanics_score or '-' }}</td>
<td>{{ eval.cohesion_score or '-' }}</td> <td>{{ eval.cohesion_score or '-' }}</td>
<td>{{ eval.communication_score or '-' }}</td> <td>{{ eval.communication_score or '-' }}</td>
+14 -8
View File
@@ -77,22 +77,28 @@
</span> </span>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<span class="detail-label"><i class="fas fa-chart-line"></i> TRN (Tracker Network)</span> <span class="detail-label"><i class="fas fa-chart-line"></i> Games & TRN</span>
<span class="detail-value"> <span class="detail-value">
{% if user.gamertags %} {% set games_list = user.get_games_list() %}
{% if games_list %}
<div style="display: flex; flex-direction: column; gap: 8px;"> <div style="display: flex; flex-direction: column; gap: 8px;">
{% for gamertag in user.gamertags %} {% for game in games_list %}
{% set gt = user.gamertags | selectattr('game', 'equalto', game) | first %}
<div> <div>
<span class="badge badge-esport" style="margin-right: 8px;">{{ gamertag.game }}</span> {% if gt and gt.get_trn_url() %}
<a href="{{ gamertag.get_trn_url() }}" target="_blank" rel="noopener noreferrer" class="trn-link"> <a href="{{ gt.get_trn_url() }}" target="_blank" rel="noopener noreferrer" class="trn-link">
<i class="fas fa-external-link-alt"></i> {{ gamertag.gamertag }} <span class="badge badge-esport" style="margin-right: 8px;">{{ game }}</span>
{% if gamertag.platform %}<small>({{ gamertag.platform }})</small>{% endif %} <i class="fas fa-external-link-alt"></i> {{ gt.gamertag }}
{% if gt.platform %}<small>({{ gt.platform }})</small>{% endif %}
</a> </a>
{% else %}
<span class="badge badge-esport">{{ game }}</span>
{% endif %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% else %} {% else %}
<span class="text-muted">Not connected</span> <span class="text-muted">Not specified</span>
{% endif %} {% endif %}
</span> </span>
</div> </div>
+80 -57
View File
@@ -12,64 +12,87 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="card"> <div class="tryouts-grid">
<div class="card-body"> {% for tryout in tryouts %}
<div class="table-container"> <div class="card tryout-card">
<table class="table"> <div class="card-header">
<thead> <h3 class="tryout-title">{{ tryout.title }}</h3>
<tr> <span class="badge badge-{{ tryout.status }}">{{ tryout.status | replace('_', ' ') | title }}</span>
<th>Title</th> </div>
<th>Target Team</th> <div class="card-body">
<th>Date</th> <div class="tryout-info-grid">
<th>Location</th> <div class="info-item">
<th>Status</th> <i class="fas fa-gamepad info-icon"></i>
<th>Players</th> <span class="info-label">Game</span>
<th>Evaluations</th> <span class="info-value">{{ tryout.game }}</span>
<th>Actions</th> </div>
</tr> <div class="info-item">
</thead> <i class="fas fa-calendar info-icon"></i>
<tbody> <span class="info-label">Date</span>
{% for tryout in tryouts %} <span class="info-value">{{ tryout.date.strftime('%b %d, %Y') }}</span>
<tr> </div>
<td class="cell-title">{{ tryout.title }}</td> <div class="info-item">
<td>{{ tryout.target_org_team.name if tryout.target_org_team else '-' }}</td> <i class="fas fa-map-marker-alt info-icon"></i>
<td>{{ tryout.date.strftime('%b %d, %Y') }}</td> <span class="info-label">Location</span>
<td>{{ tryout.location or 'TBD' }}</td> <span class="info-value">{{ tryout.location or 'TBD' }}</span>
<td> </div>
<span class="badge badge-{{ tryout.status }}"> <div class="info-item">
{{ tryout.status | replace('_', ' ') | title }} <i class="fas fa-users info-icon"></i>
</span> <span class="info-label">Players</span>
</td> <span class="info-value">{{ tryout.registrations.count() }}</span>
<td>{{ tryout.registrations.count() }}</td> </div>
<td>{{ tryout.evaluations.count() }}</td> {% if current_user.can_evaluate() %}
<td> <div class="info-item">
<a href="{{ url_for('tryouts.view_tryout', tryout_id=tryout.id) }}" class="btn btn-sm btn-outline"> <i class="fas fa-clipboard-check info-icon"></i>
<i class="fas fa-eye"></i> View <span class="info-label">Evaluations</span>
</a> <span class="info-value">{{ tryout.evaluations.count() }}</span>
{% if current_user.can_evaluate() %} </div>
<a href="{{ url_for('evaluations.players_to_evaluate', tryout_id=tryout.id) }}" class="btn btn-sm btn-primary"> {% endif %}
<i class="fas fa-clipboard-check"></i> Evaluate {% if tryout.target_org_team %}
</a> <div class="info-item">
{% endif %} <i class="fas fa-flag info-icon"></i>
</td> <span class="info-label">Target Team</span>
</tr> <span class="info-value">{{ tryout.target_org_team.name }}</span>
{% else %} </div>
<tr> {% endif %}
<td colspan="8" class="text-center"> {% if tryout.max_players %}
<div class="empty-state"> <div class="info-item">
<i class="fas fa-calendar-times"></i> <i class="fas fa-user-friends info-icon"></i>
<h3>No tryouts found</h3> <span class="info-label">Max Players</span>
{% if current_user.can_manage_tryouts() %} <span class="info-value">{{ tryout.max_players }}</span>
<p>Get started by creating a new tryout.</p> </div>
<a href="{{ url_for('tryouts.create_tryout') }}" class="btn btn-primary">Create Tryout</a> {% endif %}
{% endif %} </div>
</div> {% if tryout.description %}
</td> <div class="tryout-description mt-3">
</tr> <p>{{ tryout.description | truncate(120) }}</p>
{% endfor %} </div>
</tbody> {% endif %}
</table> </div>
<div class="card-footer">
<a href="{{ url_for('tryouts.view_tryout', tryout_id=tryout.id) }}" class="btn btn-sm btn-outline">
<i class="fas fa-eye"></i> View Details
</a>
{% if current_user.can_evaluate() %}
<a href="{{ url_for('evaluations.players_to_evaluate', tryout_id=tryout.id) }}" class="btn btn-sm btn-primary">
<i class="fas fa-clipboard-check"></i> Evaluate
</a>
{% endif %}
</div> </div>
</div> </div>
{% else %}
<div class="card" style="grid-column: 1 / -1;">
<div class="card-body text-center">
<div class="empty-state">
<i class="fas fa-calendar-times"></i>
<h3>No tryouts found</h3>
{% if current_user.can_manage_tryouts() %}
<p>Get started by creating a new tryout.</p>
<a href="{{ url_for('tryouts.create_tryout') }}" class="btn btn-primary">Create Tryout</a>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div> </div>
{% endblock %} {% endblock %}
+193 -191
View File
@@ -246,204 +246,206 @@
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
</div>
{% if can_view_calendar %} {% if can_view_calendar %}
<div class="card"> <div class="card tryout-schedule-card mb-4">
<div class="card-header"> <div class="card-header">
<h3><i class="fas fa-futbol"></i> Schedule</h3> <h3><i class="fas fa-futbol"></i> Schedule</h3>
{% if can_edit %} {% if can_edit %}
<div class="card-actions"> <div class="card-actions">
<a href="{{ url_for('matches.create_match', tryout_id=tryout.id) }}" class="btn btn-sm btn-success"> <a href="{{ url_for('matches.create_match', tryout_id=tryout.id) }}" class="btn btn-sm btn-success">
<i class="fas fa-plus"></i> Schedule Match <i class="fas fa-plus"></i> Schedule Match
</a> </a>
<a href="{{ url_for('users.add_note_from_tryout', tryout_id=tryout.id) }}" class="btn btn-sm btn-primary"> <a href="{{ url_for('users.add_note_from_tryout', tryout_id=tryout.id) }}" class="btn btn-sm btn-primary">
<i class="fas fa-sticky-note"></i> Add Note <i class="fas fa-sticky-note"></i> Add Note
</a> </a>
</div>
{% endif %}
</div>
<div class="card-body">
{% if matches %}
<!-- Mini Calendar -->
<div id="mini-calendar" style="min-height: 300px;"></div>
{% else %}
<!-- No matches yet - show message -->
<div class="text-center py-4">
<i class="fas fa-calendar-alt fa-3x text-muted mb-3"></i>
<p class="text-muted">No matches scheduled yet. Check back later!</p>
</div>
{% endif %}
{% if matches %}
<!-- Matches Table -->
<div class="table-container mt-3">
<table class="table">
<thead>
<tr>
<th>Match</th>
<th>Type</th>
<th>Date</th>
<th>Participants</th>
<th>Time</th>
<th>Status</th>
{% if can_edit %}
<th>Actions</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for item in match_data %}
{% set m = item.match %}
{% set participants = item.participants %}
<tr>
<td class="cell-title">{{ m.title }}</td>
<td>
<span class="badge badge-{{ 'success' if m.match_type in ['team_vs_team', 'player_vs_player'] else 'warning' }}">
{% if m.match_type == 'team_vs_team' %}
Team vs Team
{% elif m.match_type == 'player_vs_player' %}
Player vs Player
{% else %}
Player Scrim
{% endif %}
</span>
</td>
<td>{{ m.date.strftime('%m/%d/%Y') }}</td>
<td>
{% if m.match_type == 'team_vs_team' %}
<div class="match-teams">
<div class="match-team">
<span class="team-name">{{ m.team1.name if m.team1 else '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">{{ 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 %}
</div>
</div>
{% elif m.match_type == 'player_vs_player' %}
<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 %}
{{ participants | join(', ') }}
{% endif %}
</td>
<td>
{% if m.start_time and m.end_time %}
{{ m.start_time.strftime('%H:%M') }} - {{ m.end_time.strftime('%H:%M') }}
{% else %}
TBD
{% endif %}
</td>
<td>
<span class="badge badge-{{ m.status }}">{{ m.status }}</span>
</td>
{% if can_edit %}
<td>
<a href="{{ url_for('matches.edit_match', match_id=m.id) }}" class="btn btn-sm btn-outline">
<i class="fas fa-edit"></i> Edit
</a>
<a href="{{ url_for('users.add_note_from_match', match_id=m.id) }}" class="btn btn-sm btn-primary" title="Add Note for this Match">
<i class="fas fa-sticky-note"></i> Note
</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</div> </div>
{% endif %}
</div> </div>
{% endif %} <div class="card-body">
{% if matches %}
<div class="card"> <!-- Matches Table -->
<div class="card-header"> <div class="table-container">
<h3><i class="fas fa-star"></i> Evaluation Summary</h3> <table class="table">
<thead>
<tr>
<th>Match</th>
<th>Type</th>
<th>Date</th>
<th>Participants</th>
<th>Time</th>
<th>Status</th>
{% if can_edit %}
<th>Actions</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for item in match_data %}
{% set m = item.match %}
{% set participants = item.participants %}
<tr>
<td class="cell-title">{{ m.title }}</td>
<td>
<span class="badge badge-{{ 'success' if m.match_type in ['team_vs_team', 'player_vs_player'] else 'warning' }}">
{% if m.match_type == 'team_vs_team' %}
Team vs Team
{% elif m.match_type == 'player_vs_player' %}
Player vs Player
{% else %}
Player Scrim
{% endif %}
</span>
</td>
<td>{{ m.date.strftime('%m/%d/%Y') }}</td>
<td>
{% if m.match_type == 'team_vs_team' %}
<div class="match-teams">
<div class="match-team">
<span class="team-name">{{ m.team1.name if m.team1 else '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">{{ 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 %}
</div>
</div>
{% elif m.match_type == 'player_vs_player' %}
<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 %}
{{ participants | join(', ') }}
{% endif %}
</td>
<td>
{% if m.start_time and m.end_time %}
{{ m.start_time.strftime('%H:%M') }} - {{ m.end_time.strftime('%H:%M') }}
{% else %}
TBD
{% endif %}
</td>
<td>
<span class="badge badge-{{ m.status }}">{{ m.status }}</span>
</td>
{% if can_edit %}
<td>
<a href="{{ url_for('matches.edit_match', match_id=m.id) }}" class="btn btn-sm btn-outline">
<i class="fas fa-edit"></i> Edit
</a>
<a href="{{ url_for('users.add_note_from_match', match_id=m.id) }}" class="btn btn-sm btn-primary" title="Add Note for this Match">
<i class="fas fa-sticky-note"></i> Note
</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div> </div>
<div class="card-body"> {% endif %}
<div class="table-container">
<table class="table"> {% if matches %}
<thead> <!-- Mini Calendar -->
<tr> <div id="mini-calendar" style="min-height: 300px; margin-top: 20px;"></div>
<th>Player</th> {% else %}
<th>Evaluator</th> <!-- No matches yet - show message -->
<th>Mecanics</th> <div class="text-center py-4">
<th>Cohesion</th> <i class="fas fa-calendar-alt fa-3x text-muted mb-3"></i>
<th>Communication</th> <p class="text-muted">No matches scheduled yet. Check back later!</p>
<th>Gamesense</th> </div>
<th>Versatility</th> {% endif %}
<th>Discipline</th> </div>
<th>Analysis</th> </div>
<th>Sport Ethics</th> {% endif %}
<th>Mental</th>
<th>Overall</th> {% if current_user.can_evaluate() %}
<th>Recommendation</th> <div class="card">
</tr> <div class="card-header">
</thead> <h3><i class="fas fa-star"></i> Evaluation Summary</h3>
<tbody> </div>
{% for eval in evaluations %} <div class="card-body">
<tr> <div class="table-container">
<td>{{ eval.player.full_name }}</td> <table class="table">
<td>{{ eval.evaluator.full_name }}</td> <thead>
<td>{{ eval.mecanics_score or '-' }}</td> <tr>
<td>{{ eval.cohesion_score or '-' }}</td> <th>Player</th>
<td>{{ eval.communication_score or '-' }}</td> <th>Evaluator</th>
<td>{{ eval.gamesense_score or '-' }}</td> <th>Mecanics</th>
<td>{{ eval.versatility_score or '-' }}</td> <th>Cohesion</th>
<td>{{ eval.discipline_score or '-' }}</td> <th>Communication</th>
<td>{{ eval.analysis_score or '-' }}</td> <th>Gamesense</th>
<td>{{ eval.sport_ethics_score or '-' }}</td> <th>Versatility</th>
<td>{{ eval.mental_score or '-' }}</td> <th>Discipline</th>
<td><span class="score">{{ eval.overall_score or '-' }}</span></td> <th>Analysis</th>
<td>{{ eval.position_recommendation or '-' }}</td> <th>Sport Ethics</th>
</tr> <th>Mental</th>
{% else %} <th>Overall</th>
<tr> <th>Recommendation</th>
<td colspan="13" class="text-center">No evaluations yet.</td> </tr>
</tr> </thead>
{% endfor %} <tbody>
</tbody> {% for eval in evaluations %}
</table> <tr>
</div> <td>{{ eval.player.full_name }}</td>
<td>{{ eval.evaluator.full_name }}</td>
<td>{{ eval.mecanics_score or '-' }}</td>
<td>{{ eval.cohesion_score or '-' }}</td>
<td>{{ eval.communication_score or '-' }}</td>
<td>{{ eval.gamesense_score or '-' }}</td>
<td>{{ eval.versatility_score or '-' }}</td>
<td>{{ eval.discipline_score or '-' }}</td>
<td>{{ eval.analysis_score or '-' }}</td>
<td>{{ eval.sport_ethics_score or '-' }}</td>
<td>{{ eval.mental_score or '-' }}</td>
<td><span class="score">{{ eval.overall_score or '-' }}</span></td>
<td>{{ eval.position_recommendation or '-' }}</td>
</tr>
{% else %}
<tr>
<td colspan="13" class="text-center">No evaluations yet.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
{% endif %}
</div> </div>
<script> <script>