182 lines
8.5 KiB
HTML
182 lines
8.5 KiB
HTML
{% 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 = {% if current_user.can_schedule_matches() %}true{% else %}false{% endif %};
|
|
|
|
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);
|
|
},
|
|
slotMinTime: '12:00:00',
|
|
slotMaxTime: '24:00:00'
|
|
});
|
|
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' || props.match_type === 'player_vs_player' ? 'success' : 'warning')) + '">';
|
|
content += (type === 'tryout' ? 'Tryout' : (props.match_type === 'team_vs_team' ? 'Team Match' : (props.match_type === 'player_vs_player' ? 'Player Match' : 'Player Scrim'))) + '</span>';
|
|
content += '</span></div>';
|
|
content += '<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>';
|
|
|
|
// Add team separation for matches
|
|
if (type === 'match' && props.participants) {
|
|
content += '<div class="detail-item full-width"><span class="detail-label">Teams</span><span class="detail-value">';
|
|
if (props.match_type === 'team_vs_team') {
|
|
// For team vs team, participants is "Team1 vs Team2"
|
|
var teams = props.participants.split(' vs ');
|
|
if (teams.length >= 2) {
|
|
content += '<div class="match-teams">';
|
|
content += '<div class="match-team"><span class="team-name">' + teams[0] + '</span></div>';
|
|
content += '<div class="match-vs">vs</div>';
|
|
content += '<div class="match-team"><span class="team-name">' + teams[1] + '</span></div>';
|
|
content += '</div>';
|
|
} else {
|
|
content += props.participants;
|
|
}
|
|
} else if (props.match_type === 'player_vs_player') {
|
|
// For player vs player, we need to parse the participants
|
|
// The format is "player1, player2 vs player3, player4"
|
|
var parts = props.participants.split(' vs ');
|
|
if (parts.length >= 2) {
|
|
content += '<div class="match-teams">';
|
|
content += '<div class="match-team"><span class="team-name">Team 1</span><ul class="team-players-list"><li>' + parts[0].split(', ').join('</li><li>') + '</li></ul></div>';
|
|
content += '<div class="match-vs">vs</div>';
|
|
content += '<div class="match-team"><span class="team-name">Team 2</span><ul class="team-players-list"><li>' + parts[1].split(', ').join('</li><li>') + '</li></ul></div>';
|
|
content += '</div>';
|
|
} else {
|
|
content += props.participants;
|
|
}
|
|
} else {
|
|
// For player scrim, just show the list
|
|
content += props.participants;
|
|
}
|
|
content += '</span></div>';
|
|
}
|
|
|
|
if (props.description) {
|
|
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 %} |