Files
team-tryouts/app/templates/pages/one_on_one.html
T
2026-08-25 13:29:22 -04:00

332 lines
13 KiB
HTML

{% extends "layouts/base.html" %}
{% block title %}One on One - TryoutPro{% endblock %}
{% block page_title %}One on One{% endblock %}
{% block breadcrumb %}<span class="breadcrumb">Home / One on One</span>{% endblock %}
{% block content %}
<!-- My One on One Requests Tracker -->
<div class="card mb-4">
<div class="card-header">
<h3><i class="fas fa-list-check"></i> My One on One Requests</h3>
</div>
<div class="card-body">
{% if my_requests %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Coach</th>
<th>Team</th>
<th>Date</th>
<th>Time</th>
<th>Discussion Points</th>
<th>Status</th>
<th>Coach Response</th>
</tr>
</thead>
<tbody>
{% for req in my_requests %}
<tr>
<td>{{ req.coach.full_name if req.coach else 'Unknown Coach' }}</td>
<td>{{ req.team.name if req.team else '—' }}</td>
<td>{{ req.date.strftime('%b %d, %Y') }}</td>
<td>{{ req.start_time.strftime('%I:%M %p') }} - {{ req.end_time.strftime('%I:%M %p') }}</td>
<td>{{ req.points or 'N/A' }}</td>
<td>
{% if req.status == 'pending' %}
<span class="badge badge-warning"><i class="fas fa-clock"></i> Pending</span>
{% elif req.status == 'approved' %}
<span class="badge badge-success"><i class="fas fa-check-circle"></i> Approved</span>
{% elif req.status == 'rejected' %}
<span class="badge badge-danger"><i class="fas fa-times-circle"></i> Rejected</span>
{% endif %}
</td>
<td>
{% if req.status == 'approved' %}
<span class="text-success">Session confirmed!</span>
{% elif req.status == 'rejected' %}
{% if req.coach_rejection_message %}
<span class="text-danger small">{{ req.coach_rejection_message }}</span>
{% else %}
<span class="text-muted small">Coach is unavailable</span>
{% endif %}
{% else %}
<span class="text-muted small">Awaiting coach response...</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-muted">You haven't made any One on One requests yet.</p>
{% endif %}
</div>
</div>
<!-- One on One Request Section -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-calendar-check"></i> Request One on One Session</h3>
</div>
<div class="card-body">
{% if coach_options %}
<form method="POST" action="{{ url_for('users.one_on_one') }}" class="form" id="oneOnOneForm">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div class="form-row">
<div class="form-group col-6">
<label for="coach_id">Select Coach</label>
<select name="coach_id" id="coach_id" class="form-select" onchange="onCoachChange()" required>
<option value="">-- Select Coach --</option>
{% for c in coach_options %}
<option value="{{ c.coach_id }}">{{ c.coach_name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group col-6">
<label for="org_team_id">Select Team <span class="text-muted">(optional)</span></label>
<select name="org_team_id" id="org_team_id" class="form-select">
<option value="">-- Any Team --</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="date">Select Date</label>
<select name="date" id="date" class="form-select" onchange="updateTimeSlots()" required>
<option value="">-- Select Coach First --</option>
</select>
</div>
<div class="form-group">
<label for="start_time">Start Time</label>
<select name="start_time" id="start_time" class="form-select" onchange="updateEndTimeOptions()" required>
<option value="">-- Select Date First --</option>
</select>
</div>
<div class="form-group">
<label for="end_time">End Time</label>
<select name="end_time" id="end_time" class="form-select" required>
<option value="">-- Select Start Time First --</option>
</select>
</div>
</div>
<div class="form-group">
<label for="points">Discussion Points <span class="text-muted">(What would you like to discuss?)</span></label>
<textarea name="points" id="points" class="form-textarea" placeholder="Enter topics you'd like to cover in your One on One session..." rows="4"></textarea>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="fas fa-paper-plane"></i> Send Request
</button>
</div>
</form>
{% else %}
<p class="text-muted">You need to be assigned to a team with a coach to request a One on One session.</p>
{% endif %}
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
// Coach options injected server-side
const COACH_OPTIONS = {{ coach_options | tojson }};
// Time slots from 8:00 AM to 10:00 PM
const TIME_SLOTS = [];
for (let h = 8; h <= 22; h++) {
for (let m = 0; m < 60; m += 30) {
const displayHour = h > 12 ? h - 12 : h;
const displayAmpm = h >= 12 ? 'PM' : 'AM';
const timeStr = (h < 10 ? '0' : '') + h + ':' + (m < 10 ? '0' : '') + m;
const displayTime = displayHour + ':' + (m < 10 ? '0' : '') + m + ' ' + displayAmpm;
TIME_SLOTS.push({ time: timeStr, display: displayTime });
}
}
const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
let coachAvailability = [];
// Helper to convert "HH:MM" to minutes since midnight
function toMinutes(timeStr) {
const parts = timeStr.split(':');
return parseInt(parts[0]) * 60 + parseInt(parts[1]);
}
// Build date dropdown for the next 14 days filtered to days the coach has availability
function buildDateOptions() {
const dateSelect = document.getElementById('date');
dateSelect.innerHTML = '<option value="">-- Select Date --</option>';
const availableDays = new Set(coachAvailability.map(av => av.day_of_week));
if (availableDays.size === 0) {
return;
}
const today = new Date();
for (let i = 0; i < 14; i++) {
const d = new Date(today);
d.setDate(today.getDate() + i);
if (availableDays.has(d.getDay())) {
const value = d.toISOString().split('T')[0];
const display = d.toLocaleDateString('en-US', {
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'
});
const option = document.createElement('option');
option.value = value;
option.setAttribute('data-day', d.getDay());
option.textContent = display;
dateSelect.appendChild(option);
}
}
// Reset dependent dropdowns
document.getElementById('start_time').innerHTML = '<option value="">-- Select Date First --</option>';
document.getElementById('end_time').innerHTML = '<option value="">-- Select Start Time First --</option>';
}
// Populate team dropdown for the selected coach
function updateTeamOptions(coachId) {
const teamSelect = document.getElementById('org_team_id');
teamSelect.innerHTML = '<option value="">-- Any Team --</option>';
const coach = COACH_OPTIONS.find(c => c.coach_id === coachId);
if (!coach) return;
coach.teams.forEach(team => {
const option = document.createElement('option');
option.value = team.team_id;
option.textContent = team.team_name;
teamSelect.appendChild(option);
});
}
// Fetch availability for the selected coach
function fetchCoachAvailability(coachId) {
coachAvailability = [];
if (!coachId) {
buildDateOptions();
return;
}
fetch(`/users/one-on-one/coaches/${coachId}/availability`)
.then(response => response.json())
.then(data => {
coachAvailability = data.availability || [];
buildDateOptions();
})
.catch(error => {
console.error('Error loading coach availability:', error);
coachAvailability = [];
buildDateOptions();
});
}
function onCoachChange() {
const coachId = parseInt(document.getElementById('coach_id').value);
updateTeamOptions(coachId);
fetchCoachAvailability(coachId);
}
function updateTimeSlots() {
const dateSelect = document.getElementById('date');
const startTimeSelect = document.getElementById('start_time');
const selectedOption = dateSelect.options[dateSelect.selectedIndex];
if (!selectedOption || !selectedOption.value) {
startTimeSelect.innerHTML = '<option value="">-- Select Date First --</option>';
document.getElementById('end_time').innerHTML = '<option value="">-- Select Start Time First --</option>';
return;
}
const dayOfWeek = parseInt(selectedOption.getAttribute('data-day'));
const dayAvailability = coachAvailability.filter(av => av.day_of_week === dayOfWeek);
const availableMinutes = [];
dayAvailability.forEach(av => {
const startMinutes = toMinutes(av.start_time);
const endMinutes = toMinutes(av.end_time);
for (let m = startMinutes; m < endMinutes; m += 30) {
availableMinutes.push(m);
}
});
availableMinutes.sort((a, b) => a - b);
startTimeSelect.innerHTML = '<option value="">-- Select Start Time --</option>';
availableMinutes.forEach(m => {
const hour = Math.floor(m / 60);
const minute = m % 60;
const timeStr = (hour < 10 ? '0' : '') + hour + ':' + (minute < 10 ? '0' : '') + minute;
const slotData = TIME_SLOTS.find(s => s.time === timeStr);
if (slotData) {
const option = document.createElement('option');
option.value = slotData.time;
option.textContent = slotData.display;
startTimeSelect.appendChild(option);
}
});
updateEndTimeOptions();
}
function updateEndTimeOptions() {
const dateSelect = document.getElementById('date');
const startTimeSelect = document.getElementById('start_time');
const endTimeSelect = document.getElementById('end_time');
const selectedOption = dateSelect.options[dateSelect.selectedIndex];
if (!selectedOption || !selectedOption.value) {
endTimeSelect.innerHTML = '<option value="">-- Select Start Time First --</option>';
return;
}
const dayOfWeek = parseInt(selectedOption.getAttribute('data-day'));
const selectedStart = startTimeSelect.value;
if (!selectedStart) {
endTimeSelect.innerHTML = '<option value="">-- Select Start Time First --</option>';
return;
}
const dayAvailability = coachAvailability.filter(av => av.day_of_week === dayOfWeek);
const availableMinutes = [];
dayAvailability.forEach(av => {
const startMinutes = toMinutes(av.start_time);
const endMinutes = toMinutes(av.end_time);
for (let m = startMinutes; m < endMinutes; m += 30) {
availableMinutes.push(m);
}
});
const startMinutesVal = toMinutes(selectedStart);
const validEndTimes = availableMinutes.filter(m => m > startMinutesVal).sort((a, b) => a - b);
endTimeSelect.innerHTML = '<option value="">-- Select End Time --</option>';
validEndTimes.forEach(m => {
const hour = Math.floor(m / 60);
const minute = m % 60;
const timeStr = (hour < 10 ? '0' : '') + hour + ':' + (minute < 10 ? '0' : '') + minute;
const slotData = TIME_SLOTS.find(s => s.time === timeStr);
if (slotData) {
const option = document.createElement('option');
option.value = slotData.time;
option.textContent = slotData.display;
endTimeSelect.appendChild(option);
}
});
}
document.addEventListener('DOMContentLoaded', function() {
if (COACH_OPTIONS.length > 0) {
onCoachChange();
}
});
</script>
{% endblock %}