ajout de présence des joueurs sur un matchs
This commit is contained in:
@@ -6,6 +6,8 @@ instance/
|
|||||||
documents/
|
documents/
|
||||||
|
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
*.cpython-313.pyc
|
||||||
|
*.cpython-312.pyc
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -636,6 +636,7 @@ class MatchParticipant(db.Model):
|
|||||||
player_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
player_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||||
team_side = db.Column(db.Integer, nullable=True) # 1 for team 1, 2 for team 2 (for player_vs_player matches)
|
team_side = db.Column(db.Integer, nullable=True) # 1 for team 1, 2 for team 2 (for player_vs_player matches)
|
||||||
position = db.Column(db.String(50), nullable=True) # Position for this match
|
position = db.Column(db.String(50), nullable=True) # Position for this match
|
||||||
|
attendance_confirmed = db.Column(db.Boolean, default=False) # Whether the player confirmed via Discord or manual toggle
|
||||||
added_at = db.Column(db.DateTime, default=datetime.utcnow)
|
added_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
|
|
||||||
player = db.relationship('User')
|
player = db.relationship('User')
|
||||||
|
|||||||
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.
+1
-1
@@ -6,7 +6,7 @@ This module provides the main dashboard view with role-specific statistics.
|
|||||||
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, Match, MatchParticipant
|
from models import User, Tryout, Evaluation, TryoutRegistration, Team, TeamMember, Match, MatchParticipant, OrgTeam
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
|||||||
+116
-25
@@ -356,11 +356,22 @@ def create_match(tryout_id):
|
|||||||
team2_id = request.form.get('team2_id')
|
team2_id = request.form.get('team2_id')
|
||||||
match.team1_id = int(team1_id) if team1_id else None
|
match.team1_id = int(team1_id) if team1_id else None
|
||||||
match.team2_id = int(team2_id) if team2_id else None
|
match.team2_id = int(team2_id) if team2_id else None
|
||||||
# Get players from both teams
|
# Create MatchParticipant records for all team members AND get notified player IDs
|
||||||
|
notified_participant_ids = []
|
||||||
if match.team1_id:
|
if match.team1_id:
|
||||||
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team1_id).all()])
|
for m in TeamMember.query.filter_by(team_id=match.team1_id).all():
|
||||||
|
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=1)
|
||||||
|
db.session.add(participant)
|
||||||
|
db.session.flush()
|
||||||
|
notified_participant_ids.append(participant.id)
|
||||||
|
notified_player_ids.append(m.player_id)
|
||||||
if match.team2_id:
|
if match.team2_id:
|
||||||
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team2_id).all()])
|
for m in TeamMember.query.filter_by(team_id=match.team2_id).all():
|
||||||
|
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=2)
|
||||||
|
db.session.add(participant)
|
||||||
|
db.session.flush()
|
||||||
|
notified_participant_ids.append(participant.id)
|
||||||
|
notified_player_ids.append(m.player_id)
|
||||||
|
|
||||||
# Handle player vs player matches
|
# Handle player vs player matches
|
||||||
elif match_type == 'player_vs_player':
|
elif match_type == 'player_vs_player':
|
||||||
@@ -398,17 +409,17 @@ def create_match(tryout_id):
|
|||||||
event_date_str = date_obj.strftime('%Y-%m-%d')
|
event_date_str = date_obj.strftime('%Y-%m-%d')
|
||||||
event_time_str = f"{start_time.strftime('%I:%M %p')} - {end_time.strftime('%I:%M %p')}" if start_time and end_time else 'TBD'
|
event_time_str = f"{start_time.strftime('%I:%M %p')} - {end_time.strftime('%I:%M %p')}" if start_time and end_time else 'TBD'
|
||||||
|
|
||||||
# For team_vs_team, notify all players but use match.id (no individual confirmation)
|
# Send Discord notifications with proper participant reference IDs
|
||||||
# For player_vs_player/player_scrim, notify each player individually with participant ID
|
|
||||||
if match_type == 'team_vs_team':
|
if match_type == 'team_vs_team':
|
||||||
for player_id in notified_player_ids:
|
for i, player_id in enumerate(notified_player_ids):
|
||||||
|
reference_id = notified_participant_ids[i] if i < len(notified_participant_ids) else match.id
|
||||||
send_schedule_notification(
|
send_schedule_notification(
|
||||||
user_id=player_id,
|
user_id=player_id,
|
||||||
event_type='match',
|
event_type='match',
|
||||||
event_title=match.title,
|
event_title=match.title,
|
||||||
event_date=event_date_str,
|
event_date=event_date_str,
|
||||||
event_time=event_time_str,
|
event_time=event_time_str,
|
||||||
reference_id=match.id
|
reference_id=reference_id
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
for i, player_id in enumerate(notified_player_ids):
|
for i, player_id in enumerate(notified_player_ids):
|
||||||
@@ -500,16 +511,38 @@ def edit_match(match_id):
|
|||||||
notified_player_ids = []
|
notified_player_ids = []
|
||||||
|
|
||||||
# Handle team vs team matches
|
# Handle team vs team matches
|
||||||
|
notified_participant_ids = []
|
||||||
if match.match_type == 'team_vs_team':
|
if match.match_type == 'team_vs_team':
|
||||||
team1_id = request.form.get('team1_id')
|
team1_id = request.form.get('team1_id')
|
||||||
team2_id = request.form.get('team2_id')
|
team2_id = request.form.get('team2_id')
|
||||||
match.team1_id = int(team1_id) if team1_id else None
|
new_team1_id = int(team1_id) if team1_id else None
|
||||||
match.team2_id = int(team2_id) if team2_id else None
|
new_team2_id = int(team2_id) if team2_id else None
|
||||||
# Get players from both teams
|
|
||||||
if match.team1_id:
|
# If teams changed, recreate MatchParticipant records
|
||||||
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team1_id).all()])
|
if new_team1_id != match.team1_id or new_team2_id != match.team2_id:
|
||||||
if match.team2_id:
|
MatchParticipant.query.filter_by(match_id=match.id).delete()
|
||||||
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team2_id).all()])
|
match.team1_id = new_team1_id
|
||||||
|
match.team2_id = new_team2_id
|
||||||
|
if match.team1_id:
|
||||||
|
for m in TeamMember.query.filter_by(team_id=match.team1_id).all():
|
||||||
|
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=1)
|
||||||
|
db.session.add(participant)
|
||||||
|
db.session.flush()
|
||||||
|
notified_participant_ids.append(participant.id)
|
||||||
|
notified_player_ids.append(m.player_id)
|
||||||
|
if match.team2_id:
|
||||||
|
for m in TeamMember.query.filter_by(team_id=match.team2_id).all():
|
||||||
|
participant = MatchParticipant(match_id=match.id, player_id=m.player_id, team_side=2)
|
||||||
|
db.session.add(participant)
|
||||||
|
db.session.flush()
|
||||||
|
notified_participant_ids.append(participant.id)
|
||||||
|
notified_player_ids.append(m.player_id)
|
||||||
|
else:
|
||||||
|
# Teams didn't change, still get notified player IDs
|
||||||
|
if match.team1_id:
|
||||||
|
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team1_id).all()])
|
||||||
|
if match.team2_id:
|
||||||
|
notified_player_ids.extend([m.player_id for m in TeamMember.query.filter_by(team_id=match.team2_id).all()])
|
||||||
|
|
||||||
# Handle player vs player matches - update participants
|
# Handle player vs player matches - update participants
|
||||||
elif match.match_type == 'player_vs_player':
|
elif match.match_type == 'player_vs_player':
|
||||||
@@ -565,20 +598,44 @@ def edit_match(match_id):
|
|||||||
event_date_str = match.date.strftime('%Y-%m-%d')
|
event_date_str = match.date.strftime('%Y-%m-%d')
|
||||||
end_time_val = match.end_time if match.end_time else match.start_time if match.start_time else None
|
end_time_val = match.end_time if match.end_time else match.start_time if match.start_time else None
|
||||||
event_time_str = f"{match.start_time.strftime('%I:%M %p')} - {end_time_val.strftime('%I:%M %p')}" if match.start_time and end_time_val else 'TBD'
|
event_time_str = f"{match.start_time.strftime('%I:%M %p')} - {end_time_val.strftime('%I:%M %p')}" if match.start_time and end_time_val else 'TBD'
|
||||||
for player_id in notified_player_ids:
|
if notified_participant_ids:
|
||||||
send_schedule_notification(
|
for i, player_id in enumerate(notified_player_ids):
|
||||||
user_id=player_id,
|
reference_id = notified_participant_ids[i] if i < len(notified_participant_ids) else match.id
|
||||||
event_type='match',
|
send_schedule_notification(
|
||||||
event_title=match.title,
|
user_id=player_id,
|
||||||
event_date=event_date_str,
|
event_type='match',
|
||||||
event_time=event_time_str,
|
event_title=match.title,
|
||||||
reference_id=match.id
|
event_date=event_date_str,
|
||||||
)
|
event_time=event_time_str,
|
||||||
|
reference_id=reference_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
for player_id in notified_player_ids:
|
||||||
|
send_schedule_notification(
|
||||||
|
user_id=player_id,
|
||||||
|
event_type='match',
|
||||||
|
event_title=match.title,
|
||||||
|
event_date=event_date_str,
|
||||||
|
event_time=event_time_str,
|
||||||
|
reference_id=match.id
|
||||||
|
)
|
||||||
|
|
||||||
flash('Match updated successfully!', 'success')
|
flash('Match updated successfully!', 'success')
|
||||||
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
|
return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id))
|
||||||
|
|
||||||
return render_template('pages/match_form.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids, team1_player_ids=team1_player_ids, team2_player_ids=team2_player_ids)
|
# Build participant attendance map for the template
|
||||||
|
participants_map = {}
|
||||||
|
for p in match.participants.all():
|
||||||
|
participants_map[p.player_id] = {
|
||||||
|
'participant_id': p.id,
|
||||||
|
'attendance_confirmed': p.attendance_confirmed,
|
||||||
|
'team_side': p.team_side
|
||||||
|
}
|
||||||
|
|
||||||
|
return render_template('pages/match_form.html', match=match, tryout=tryout, teams=teams,
|
||||||
|
all_players=all_players, current_player_ids=current_player_ids,
|
||||||
|
team1_player_ids=team1_player_ids, team2_player_ids=team2_player_ids,
|
||||||
|
participants_map=participants_map)
|
||||||
|
|
||||||
|
|
||||||
@matches_bp.route('/<int:match_id>/delete', methods=['POST'])
|
@matches_bp.route('/<int:match_id>/delete', methods=['POST'])
|
||||||
@@ -673,4 +730,38 @@ def api_available_players(date, time):
|
|||||||
return jsonify({'error': 'Unauthorized'}), 403
|
return jsonify({'error': 'Unauthorized'}), 403
|
||||||
|
|
||||||
player_ids = get_players_available_at_time(date, time)
|
player_ids = get_players_available_at_time(date, time)
|
||||||
return jsonify({'available_player_ids': player_ids})
|
return jsonify({'available_player_ids': player_ids})
|
||||||
|
|
||||||
|
|
||||||
|
@matches_bp.route('/<int:match_id>/toggle-presence/<int:participant_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def toggle_presence(match_id, participant_id):
|
||||||
|
"""Toggle the attendance_confirmed status for a match participant.
|
||||||
|
|
||||||
|
Accessible only to users who can manage the tryout.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
match_id: The ID of the match.
|
||||||
|
participant_id: The ID of the MatchParticipant record.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Response: JSON with new status.
|
||||||
|
"""
|
||||||
|
match = Match.query.get_or_404(match_id)
|
||||||
|
tryout = match.tryout
|
||||||
|
|
||||||
|
if not current_user.can_manage_this_tryout(tryout):
|
||||||
|
return jsonify({'error': 'Unauthorized'}), 403
|
||||||
|
|
||||||
|
participant = MatchParticipant.query.get_or_404(participant_id)
|
||||||
|
if participant.match_id != match_id:
|
||||||
|
return jsonify({'error': 'Participant does not belong to this match'}), 400
|
||||||
|
|
||||||
|
participant.attendance_confirmed = not participant.attendance_confirmed
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'participant_id': participant.id,
|
||||||
|
'attendance_confirmed': participant.attendance_confirmed,
|
||||||
|
'player_name': participant.player.username if participant.player else 'Unknown'
|
||||||
|
})
|
||||||
|
|||||||
+9
-1
@@ -271,6 +271,11 @@ def view_tryout(tryout_id):
|
|||||||
matches = Match.query.filter_by(tryout_id=tryout_id).order_by(Match.date, Match.start_time).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:
|
||||||
|
# Calculate presence stats
|
||||||
|
all_participants = list(match.participants.all())
|
||||||
|
confirmed_count = sum(1 for p in all_participants if p.attendance_confirmed)
|
||||||
|
total_count = len(all_participants)
|
||||||
|
|
||||||
if match.match_type == 'team_vs_team':
|
if match.match_type == 'team_vs_team':
|
||||||
participants = {
|
participants = {
|
||||||
'team1': match.team1.name if match.team1 else 'TBD',
|
'team1': match.team1.name if match.team1 else 'TBD',
|
||||||
@@ -289,9 +294,12 @@ def view_tryout(tryout_id):
|
|||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
participants = [p.player.username for p in match.participants.all()]
|
participants = [p.player.username for p in match.participants.all()]
|
||||||
|
|
||||||
match_data.append({
|
match_data.append({
|
||||||
'match': match,
|
'match': match,
|
||||||
'participants': participants
|
'participants': participants,
|
||||||
|
'confirmed_count': confirmed_count,
|
||||||
|
'total_count': total_count
|
||||||
})
|
})
|
||||||
|
|
||||||
return render_template('pages/view_tryout.html',
|
return render_template('pages/view_tryout.html',
|
||||||
|
|||||||
@@ -141,7 +141,19 @@
|
|||||||
<h5>{{ match.team1.name }}</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.username if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}</li>
|
<li>
|
||||||
|
{{ member.player.username if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}
|
||||||
|
{% set pdata = participants_map.get(member.player_id) %}
|
||||||
|
{% if pdata %}
|
||||||
|
<span class="presence-badge {{ 'presence-confirmed' if pdata.attendance_confirmed else 'presence-pending' }}"
|
||||||
|
data-participant-id="{{ pdata.participant_id }}"
|
||||||
|
data-match-id="{{ match.id }}"
|
||||||
|
onclick="togglePresence({{ match.id }}, {{ pdata.participant_id }}, this)"
|
||||||
|
title="Click to toggle presence">
|
||||||
|
{{ '✅ Confirmed' if pdata.attendance_confirmed else '⏳ Pending' }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="text-muted">No players assigned</li>
|
<li class="text-muted">No players assigned</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -155,7 +167,19 @@
|
|||||||
<h5>{{ match.team2.name }}</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.username if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}</li>
|
<li>
|
||||||
|
{{ member.player.username if member.player else 'Unknown Player' }}{% if member.position %} <span class="position-tag">{{ member.position }}</span>{% endif %}
|
||||||
|
{% set pdata = participants_map.get(member.player_id) %}
|
||||||
|
{% if pdata %}
|
||||||
|
<span class="presence-badge {{ 'presence-confirmed' if pdata.attendance_confirmed else 'presence-pending' }}"
|
||||||
|
data-participant-id="{{ pdata.participant_id }}"
|
||||||
|
data-match-id="{{ match.id }}"
|
||||||
|
onclick="togglePresence({{ match.id }}, {{ pdata.participant_id }}, this)"
|
||||||
|
title="Click to toggle presence">
|
||||||
|
{{ '✅ Confirmed' if pdata.attendance_confirmed else '⏳ Pending' }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="text-muted">No players assigned</li>
|
<li class="text-muted">No players assigned</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -382,6 +406,38 @@
|
|||||||
.randomize-btn:hover {
|
.randomize-btn:hover {
|
||||||
background: var(--primary-dark);
|
background: var(--primary-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Presence badge styles */
|
||||||
|
.presence-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 8px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.presence-badge:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
.presence-confirmed {
|
||||||
|
background: #d4edda;
|
||||||
|
color: #155724;
|
||||||
|
border: 1px solid #c3e6cb;
|
||||||
|
}
|
||||||
|
.presence-pending {
|
||||||
|
background: #fff3cd;
|
||||||
|
color: #856404;
|
||||||
|
border: 1px solid #ffeeba;
|
||||||
|
}
|
||||||
|
.team-members-list li {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
// Player data as simple JS object (id -> full_name)
|
// Player data as simple JS object (id -> full_name)
|
||||||
@@ -491,7 +547,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// Initialize team assignments for player_vs_player matches
|
// Initialize team assignments for player_vs_player matches
|
||||||
// Populate Team 1
|
// Populate Team 1
|
||||||
{% if match %}
|
|
||||||
initialTeam1Ids.forEach(function(pid) {
|
initialTeam1Ids.forEach(function(pid) {
|
||||||
var teamDiv = document.getElementById('team1-selection');
|
var teamDiv = document.getElementById('team1-selection');
|
||||||
var playerName = playerDataById.player_data[pid];
|
var playerName = playerDataById.player_data[pid];
|
||||||
@@ -1007,5 +1062,35 @@ function randomizeTeams() {
|
|||||||
updateHiddenInputs();
|
updateHiddenInputs();
|
||||||
updateRandomizePreview();
|
updateRandomizePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Presence toggle function
|
||||||
|
function togglePresence(matchId, participantId, badgeEl) {
|
||||||
|
fetch('/matches/' + matchId + '/toggle-presence/' + participantId, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': document.querySelector('[name="csrf_token"]').value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(response) { return response.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.error) {
|
||||||
|
alert('Error: ' + data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data.attendance_confirmed) {
|
||||||
|
badgeEl.classList.remove('presence-pending');
|
||||||
|
badgeEl.classList.add('presence-confirmed');
|
||||||
|
badgeEl.textContent = '✅ Confirmed';
|
||||||
|
} else {
|
||||||
|
badgeEl.classList.remove('presence-confirmed');
|
||||||
|
badgeEl.classList.add('presence-pending');
|
||||||
|
badgeEl.textContent = '⏳ Pending';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.error('Error toggling presence:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -278,11 +278,12 @@
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Match</th>
|
<th>Match</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Participants</th>
|
<th>Participants</th>
|
||||||
<th>Time</th>
|
<th>Time</th>
|
||||||
|
<th>Presence</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
{% if can_edit %}
|
{% if can_edit %}
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
@@ -307,6 +308,28 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ m.date.strftime('%m/%d/%Y') }}</td>
|
<td>{{ m.date.strftime('%m/%d/%Y') }}</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>
|
||||||
|
{% if item.total_count > 0 %}
|
||||||
|
<span class="presence-summary" title="{{ item.confirmed_count }} of {{ item.total_count }} confirmed">
|
||||||
|
{% if item.confirmed_count == item.total_count and item.total_count > 0 %}
|
||||||
|
<span class="badge badge-success">✅ {{ item.confirmed_count }}/{{ item.total_count }}</span>
|
||||||
|
{% elif item.confirmed_count > 0 %}
|
||||||
|
<span class="badge badge-warning">✅ {{ item.confirmed_count }}/{{ item.total_count }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge badge-secondary">⏳ 0/{{ item.total_count }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">—</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if m.match_type == 'team_vs_team' %}
|
{% if m.match_type == 'team_vs_team' %}
|
||||||
<div class="match-teams">
|
<div class="match-teams">
|
||||||
@@ -360,13 +383,6 @@
|
|||||||
{{ participants | join(', ') }}
|
{{ participants | join(', ') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</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>
|
<td>
|
||||||
<span class="badge badge-{{ m.status }}">{{ m.status }}</span>
|
<span class="badge badge-{{ m.status }}">{{ m.status }}</span>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user