ajout d'un calendrier pour sceduler des match

This commit is contained in:
cedrick2711
2026-07-14 13:35:30 -04:00
parent acb9bc3256
commit 83ee10ca64
15 changed files with 968 additions and 6 deletions
+145
View File
@@ -0,0 +1,145 @@
{% extends "layouts/base.html" %}
{% block title %}Calendar - TryoutPro{% endblock %}
{% block page_title %}Calendar{% endblock %}
{% block breadcrumb %}<span class="breadcrumb">Home / Calendar</span>{% endblock %}
{% block content %}
<div class="card">
<div class="card-header">
<h3><i class="fas fa-calendar-alt"></i> Schedule</h3>
<div class="header-actions">
<div class="btn-group" role="group">
<button type="button" class="btn btn-sm btn-outline" onclick="changeView('dayGridMonth')">
<i class="fas fa-calendar"></i> Month
</button>
<button type="button" class="btn btn-sm btn-outline" onclick="changeView('timeGridWeek')">
<i class="fas fa-calendar-week"></i> Week
</button>
<button type="button" class="btn btn-sm btn-outline" onclick="changeView('timeGridDay')">
<i class="fas fa-calendar-day"></i> Day
</button>
<button type="button" class="btn btn-sm btn-outline" onclick="changeView('listMonth')">
<i class="fas fa-list"></i> List
</button>
</div>
</div>
</div>
<div class="card-body">
<div id="calendar"></div>
</div>
</div>
<!-- Event Details Modal -->
<div id="eventModal" class="modal hidden">
<div class="modal-backdrop" onclick="hideEventModal()"></div>
<div class="modal-content">
<div class="modal-header">
<h3 id="modalTitle">Event Details</h3>
<button class="modal-close" onclick="hideEventModal()">&times;</button>
</div>
<div class="modal-body">
<div id="modalContent"></div>
<div id="modalActions" class="form-actions mt-3" style="display: none;">
<button class="btn btn-sm btn-danger" id="deleteMatchBtn" style="display: none;">
<i class="fas fa-trash"></i> Delete Match
</button>
<button class="btn btn-sm btn-primary" id="editMatchBtn" style="display: none;">
<i class="fas fa-edit"></i> Edit Match
</button>
<button class="btn btn-sm btn-primary" id="viewTryoutBtn" style="display: none;">
<i class="fas fa-eye"></i> View Tryout
</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<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>
var canScheduleMatches = {{ 'true' if current_user.can_schedule_matches() else 'false' }};
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
},
events: '/matches/api/events',
eventClick: function(info) {
showEventModal(info.event);
}
});
calendar.render();
// Store calendar in window for access
window.fcCalendar = calendar;
});
function changeView(viewName) {
if (window.fcCalendar) {
window.fcCalendar.changeView(viewName);
}
}
function showEventModal(event) {
var props = event.extendedProps;
var title = event.title;
var type = props.type;
var date = event.start ? event.start.toDateString() : '';
var content = '<div class="detail-grid">';
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 += (type === 'tryout' ? 'Tryout' : (props.match_type === 'team_vs_team' ? 'Team Match' : 'Player Scrim')) + '</span>';
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">Date</span><span class="detail-value">' + date + '</span></div>';
content += '<div class="detail-item"><span class="detail-label">Location</span><span class="detail-value">' + (props.location || 'TBD') + '</span></div>';
content += '<div class="detail-item"><span class="detail-label">Status</span><span class="detail-value">';
content += '<span class="badge badge-' + (props.status || 'scheduled') + '">' + (props.status || 'scheduled') + '</span>';
content += '</span></div>';
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>';
document.getElementById('modalTitle').textContent = type === 'tryout' ? 'Tryout Details' : 'Match Details';
document.getElementById('modalContent').innerHTML = content;
// Reset buttons
document.getElementById('deleteMatchBtn').style.display = 'none';
document.getElementById('editMatchBtn').style.display = 'none';
document.getElementById('viewTryoutBtn').style.display = 'none';
// Show action buttons for matches (coaches and above)
if (type === 'match' && canScheduleMatches) {
document.getElementById('modalActions').style.display = 'flex';
document.getElementById('editMatchBtn').style.display = 'inline-flex';
document.getElementById('editMatchBtn').onclick = function() {
window.location.href = '/matches/' + props.match_id + '/edit';
};
} else if (type === 'tryout' && canScheduleMatches) {
document.getElementById('modalActions').style.display = 'flex';
document.getElementById('viewTryoutBtn').style.display = 'inline-flex';
document.getElementById('viewTryoutBtn').onclick = function() {
window.location.href = '/tryouts/' + props.tryout_id;
};
} else {
document.getElementById('modalActions').style.display = 'none';
}
document.getElementById('eventModal').classList.remove('hidden');
}
function hideEventModal() {
document.getElementById('eventModal').classList.add('hidden');
}
</script>
{% endblock %}
+134
View File
@@ -0,0 +1,134 @@
{% extends "layouts/base.html" %}
{% block title %}Schedule Match - {{ tryout.title }} - TryoutPro{% endblock %}
{% block page_title %}Schedule Match{% endblock %}
{% block breadcrumb %}<span class="breadcrumb">Home / <a href="{{ url_for('tryouts.list_tryouts') }}">Tryouts</a> / <a href="{{ url_for('tryouts.view_tryout', tryout_id=tryout.id) }}">{{ tryout.title }}</a> / Schedule Match</span>{% endblock %}
{% block content %}
<div class="card">
<div class="card-header">
<h3><i class="fas fa-futbol"></i> Schedule Match for {{ tryout.title }}</h3>
</div>
<div class="card-body">
<form method="POST" action="{{ url_for('matches.create_match', tryout_id=tryout.id) }}" class="form">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div class="form-group">
<label for="match_type">Match Type</label>
<select name="match_type" id="match_type" class="form-select" onchange="toggleMatchType()" required>
<option value="team_vs_team">Team vs Team</option>
<option value="player_scrim">Player Scrim</option>
</select>
</div>
<div class="form-row">
<div class="form-group">
<label for="title">Match Title</label>
<input type="text" name="title" id="title" class="form-input" placeholder="e.g., Alpha vs Bravo Scrimmage" required>
</div>
<div class="form-group">
<label for="date">Date</label>
<input type="date" name="date" id="date" class="form-input" value="{{ tryout.date.strftime('%Y-%m-%d') }}" required>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="start_time">Start Time (Optional)</label>
<input type="time" name="start_time" id="start_time" class="form-input">
</div>
<div class="form-group">
<label for="end_time">End Time (Optional)</label>
<input type="time" name="end_time" id="end_time" class="form-input">
</div>
</div>
<div class="form-group">
<label for="location">Location</label>
<input type="text" name="location" id="location" class="form-input" placeholder="Match location">
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" id="description" class="form-textarea" placeholder="Optional notes about this match"></textarea>
</div>
<!-- Team vs Team Selection -->
<div id="team-vs-team-section">
<hr class="section-divider">
<h4 class="section-title"><i class="fas fa-users"></i> Select Teams</h4>
<div class="form-row">
<div class="form-group">
<label for="team1_id">Team 1</label>
<select name="team1_id" id="team1_id" class="form-select">
<option value="">-- Select Team 1 --</option>
{% for team in teams %}
<option value="{{ team.id }}">{{ team.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="team2_id">Team 2</label>
<select name="team2_id" id="team2_id" class="form-select">
<option value="">-- Select Team 2 --</option>
{% for team in teams %}
<option value="{{ team.id }}">{{ team.name }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<!-- Player Scrim Selection -->
<div id="player-scrim-section" class="hidden">
<hr class="section-divider">
<h4 class="section-title"><i class="fas fa-user-friends"></i> Select Players</h4>
<div class="form-group">
<label>Players</label>
<div class="checkbox-grid">
{% for player in all_players %}
<label class="checkbox-label">
<input type="checkbox" name="player_ids" value="{{ player.id }}">
{{ player.full_name }}
</label>
{% endfor %}
</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Schedule Match
</button>
<a href="{{ url_for('tryouts.view_tryout', tryout_id=tryout.id) }}" class="btn btn-secondary">
<i class="fas fa-times"></i> Cancel
</a>
</div>
</form>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function toggleMatchType() {
var matchType = document.getElementById('match_type').value;
var teamSection = document.getElementById('team-vs-team-section');
var playerSection = document.getElementById('player-scrim-section');
if (matchType === 'team_vs_team') {
teamSection.classList.remove('hidden');
playerSection.classList.add('hidden');
} else {
teamSection.classList.add('hidden');
playerSection.classList.remove('hidden');
}
}
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
toggleMatchType();
});
</script>
{% endblock %}
+108
View File
@@ -0,0 +1,108 @@
{% extends "layouts/base.html" %}
{% block title %}Edit Match - TryoutPro{% endblock %}
{% block page_title %}Edit Match{% endblock %}
{% block breadcrumb %}<span class="breadcrumb">Home / <a href="{{ url_for('tryouts.list_tryouts') }}">Tryouts</a> / <a href="{{ url_for('tryouts.view_tryout', tryout_id=tryout.id) }}">{{ tryout.title }}</a> / Edit Match</span>{% endblock %}
{% block content %}
<div class="card">
<div class="card-header">
<h3><i class="fas fa-futbol"></i> Edit Match</h3>
</div>
<div class="card-body">
<form method="POST" action="{{ url_for('matches.edit_match', match_id=match.id) }}" class="form">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div class="form-group">
<label for="title">Match Title</label>
<input type="text" name="title" id="title" class="form-input" value="{{ match.title }}" required>
</div>
<div class="form-row">
<div class="form-group">
<label for="date">Date</label>
<input type="date" name="date" id="date" class="form-input" value="{{ match.date.strftime('%Y-%m-%d') }}" required>
</div>
<div class="form-group">
<label for="status">Status</label>
<select name="status" id="status" class="form-select">
<option value="scheduled" {% if match.status == 'scheduled' %}selected{% endif %}>Scheduled</option>
<option value="completed" {% if match.status == 'completed' %}selected{% endif %}>Completed</option>
<option value="cancelled" {% if match.status == 'cancelled' %}selected{% endif %}>Cancelled</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="start_time">Start Time</label>
<input type="time" name="start_time" id="start_time" class="form-input" value="{{ match.start_time.strftime('%H:%M') if match.start_time else '' }}">
</div>
<div class="form-group">
<label for="end_time">End Time</label>
<input type="time" name="end_time" id="end_time" class="form-input" value="{{ match.end_time.strftime('%H:%M') if match.end_time else '' }}">
</div>
</div>
<div class="form-group">
<label for="location">Location</label>
<input type="text" name="location" id="location" class="form-input" value="{{ match.location or '' }}" placeholder="Match location">
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" id="description" class="form-textarea" placeholder="Optional notes about this match">{{ match.description or '' }}</textarea>
</div>
{% if match.match_type == 'team_vs_team' %}
<hr class="section-divider">
<h4 class="section-title"><i class="fas fa-users"></i> Teams</h4>
<div class="form-row">
<div class="form-group">
<label for="team1_id">Team 1</label>
<select name="team1_id" id="team1_id" class="form-select">
<option value="">-- Select Team 1 --</option>
{% for team in teams %}
<option value="{{ team.id }}" {% if match.team1_id == team.id %}selected{% endif %}>{{ team.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="team2_id">Team 2</label>
<select name="team2_id" id="team2_id" class="form-select">
<option value="">-- Select Team 2 --</option>
{% for team in teams %}
<option value="{{ team.id }}" {% if match.team2_id == team.id %}selected{% endif %}>{{ team.name }}</option>
{% endfor %}
</select>
</div>
</div>
{% else %}
<hr class="section-divider">
<h4 class="section-title"><i class="fas fa-user-friends"></i> Players</h4>
<div class="form-group">
<label>Players</label>
<div class="checkbox-grid">
{% for player in all_players %}
<label class="checkbox-label">
<input type="checkbox" name="player_ids" value="{{ player.id }}" {% if player.id in current_player_ids %}checked{% endif %}>
{{ player.full_name }}
</label>
{% endfor %}
</div>
</div>
{% endif %}
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Save Changes
</button>
<a href="{{ url_for('tryouts.view_tryout', tryout_id=tryout.id) }}" class="btn btn-secondary">
<i class="fas fa-times"></i> Cancel
</a>
</div>
</form>
</div>
</div>
{% endblock %}
+105 -2
View File
@@ -6,9 +6,14 @@
{% block content %}
<div class="tryout-detail">
<div class="card mb-4">
<div class="card-header">
<div class="card-header">
<h3>Tryout Details</h3>
<div class="card-actions">
{% if can_edit %}
<a href="{{ url_for('matches.create_match', tryout_id=tryout.id) }}" class="btn btn-sm btn-success">
<i class="fas fa-futbol"></i> Schedule Match
</a>
{% endif %}
{% if can_edit %}
<form method="POST" action="{{ url_for('tryouts.update_status', tryout_id=tryout.id) }}" class="inline-form">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
@@ -226,6 +231,80 @@
</div>
</div>
{% if matches %}
<div class="card mt-4">
<div class="card-header">
<h3><i class="fas fa-futbol"></i> Scheduled Matches</h3>
{% if can_edit %}
<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
</a>
{% endif %}
</div>
<div class="card-body">
<!-- Mini Calendar -->
<div id="mini-calendar" style="min-height: 300px;"></div>
<!-- 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 %}
<tr>
<td class="cell-title">{{ m.title }}</td>
<td>
<span class="badge badge-{{ 'success' if m.match_type == 'team_vs_team' else 'warning' }}">
{{ 'Team vs Team' if m.match_type == 'team_vs_team' else 'Player Scrim' }}
</span>
</td>
<td>{{ m.date.strftime('%m/%d/%Y') }}</td>
<td>
{% if m.match_type == 'team_vs_team' %}
{{ item.participants.team1 }} vs {{ item.participants.team2 }}
{% else %}
{{ item.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>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
<div class="card mt-4">
<div class="card-header">
<h3><i class="fas fa-star"></i> Evaluation Summary</h3>
@@ -274,5 +353,29 @@
<script>
function showCreateTeam() { document.getElementById('createTeamForm').classList.remove('hidden'); }
function hideCreateTeam() { document.getElementById('createTeamForm').classList.add('hidden'); }
// Mini calendar for matches
document.addEventListener('DOMContentLoaded', function() {
var miniCalendarEl = document.getElementById('mini-calendar');
if (miniCalendarEl) {
var miniCalendar = new FullCalendar.Calendar(miniCalendarEl, {
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next',
center: 'title',
right: 'dayGridMonth,timeGridWeek'
},
events: '/matches/api/events/{{ tryout.id }}',
height: '300px',
eventClick: function(info) {
// Could show match details or edit link
if (info.event.extendedProps.match_id) {
window.location.href = '/matches/' + info.event.extendedProps.match_id + '/edit';
}
}
});
miniCalendar.render();
}
});
</script>
{% endblock %}
{% endblock %}