ajout d'un calendrier pour sceduler des match
This commit is contained in:
@@ -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()">×</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 %}
|
||||
@@ -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 %}
|
||||
@@ -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 %}
|
||||
@@ -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 %}
|
||||
|
||||
Reference in New Issue
Block a user