changer ou modifier les dispo
This commit is contained in:
+9
-7
@@ -254,11 +254,17 @@ def view_user(user_id):
|
|||||||
def profile():
|
def profile():
|
||||||
"""View the current user's profile."""
|
"""View the current user's profile."""
|
||||||
contracts = None
|
contracts = None
|
||||||
|
coach_availability = []
|
||||||
if isinstance(current_user, Player):
|
if isinstance(current_user, Player):
|
||||||
contracts = Contract.query.filter_by(
|
contracts = Contract.query.filter_by(
|
||||||
player_id=current_user.id,
|
player_id=current_user.id,
|
||||||
).order_by(Contract.uploaded_at.desc()).all()
|
).order_by(Contract.uploaded_at.desc()).all()
|
||||||
return render_template('pages/profile.html', user=current_user, contracts=contracts)
|
elif isinstance(current_user, Coach):
|
||||||
|
coach_availability = CoachAvailability.query.filter_by(
|
||||||
|
coach_id=current_user.id,
|
||||||
|
).all()
|
||||||
|
return render_template('pages/profile.html', user=current_user, contracts=contracts,
|
||||||
|
coach_availability=coach_availability)
|
||||||
|
|
||||||
|
|
||||||
@users_bp.route('/profile/edit', methods=['GET', 'POST'])
|
@users_bp.route('/profile/edit', methods=['GET', 'POST'])
|
||||||
@@ -974,12 +980,8 @@ def manage_coach_availability():
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
return jsonify({'success': True})
|
return jsonify({'success': True})
|
||||||
|
|
||||||
existing_availability = CoachAvailability.query.filter_by(
|
# GET requests redirect to profile page where availability is now managed
|
||||||
coach_id=current_user.id,
|
return redirect(url_for('users.profile'))
|
||||||
).all()
|
|
||||||
|
|
||||||
return render_template('pages/coach_availability.html',
|
|
||||||
existing_availability=existing_availability)
|
|
||||||
|
|
||||||
|
|
||||||
@users_bp.route('/coach-availability/clear', methods=['POST'])
|
@users_bp.route('/coach-availability/clear', methods=['POST'])
|
||||||
|
|||||||
@@ -85,12 +85,6 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if current_user.role == 'coach' %}
|
{% if current_user.role == 'coach' %}
|
||||||
<li>
|
|
||||||
<a href="{{ url_for('users.manage_coach_availability') }}" class="{% if request.endpoint == 'users.manage_coach_availability' %}active{% endif %}">
|
|
||||||
<i class="fas fa-clock"></i>
|
|
||||||
<span>Availability</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('users.notes_dashboard') }}" class="{% if request.endpoint == 'users.notes_dashboard' or request.endpoint == 'users.manage_team_notes' or request.endpoint == 'users.manage_personal_notes' %}active{% endif %}">
|
<a href="{{ url_for('users.notes_dashboard') }}" class="{% if request.endpoint == 'users.notes_dashboard' or request.endpoint == 'users.manage_team_notes' or request.endpoint == 'users.manage_personal_notes' %}active{% endif %}">
|
||||||
<i class="fas fa-sticky-note"></i>
|
<i class="fas fa-sticky-note"></i>
|
||||||
|
|||||||
@@ -104,25 +104,6 @@
|
|||||||
<input type="password" id="password" name="password" placeholder="Enter new password">
|
<input type="password" id="password" name="password" placeholder="Enter new password">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if user.role == 'player' %}
|
|
||||||
<hr class="section-divider">
|
|
||||||
<h4 class="section-title"><i class="fas fa-clock"></i> My Disponibilities</h4>
|
|
||||||
<p class="text-muted small">Select your available time blocks for matches (5pm to 12am). Green = selected, Gray = available to select.</p>
|
|
||||||
|
|
||||||
<div id="disponibilities-grid">
|
|
||||||
<p class="text-muted">Loading...</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<button type="button" class="btn btn-primary" onclick="saveDisponibilities()">
|
|
||||||
<i class="fas fa-save"></i> Save Disponibilities
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-secondary" onclick="clearDisponibilities()">
|
|
||||||
<i class="fas fa-trash"></i> Clear All
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<a href="{{ url_for('users.profile') }}" class="btn btn-secondary">Cancel</a>
|
<a href="{{ url_for('users.profile') }}" class="btn btn-secondary">Cancel</a>
|
||||||
<button type="submit" class="btn btn-primary">Save Changes</button>
|
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||||
@@ -165,177 +146,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// Show gamertag inputs for already selected games
|
// Show gamertag inputs for already selected games
|
||||||
toggleGamertagInputs();
|
toggleGamertagInputs();
|
||||||
|
|
||||||
{% if user.role == 'player' %}
|
|
||||||
renderDisponibilityGrid();
|
|
||||||
{% endif %}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
{% if user.role == 'player' %}
|
|
||||||
// Generate time slots from 5pm (17:00) to 12am (24:00)
|
|
||||||
var TIME_SLOTS = [];
|
|
||||||
for (var h = 17; h <= 24; h++) {
|
|
||||||
for (var m = 0; m < 60; m += 30) {
|
|
||||||
if (h === 24 && m > 0) continue;
|
|
||||||
var displayHour;
|
|
||||||
var displayAmpm;
|
|
||||||
if (h === 24) {
|
|
||||||
displayHour = 12;
|
|
||||||
displayAmpm = 'AM';
|
|
||||||
} else if (h > 12) {
|
|
||||||
displayHour = h - 12;
|
|
||||||
displayAmpm = 'PM';
|
|
||||||
} else {
|
|
||||||
displayHour = h;
|
|
||||||
displayAmpm = 'PM';
|
|
||||||
}
|
|
||||||
var timeStr = (h < 10 ? '0' : '') + h + ':' + (m < 10 ? '0' : '') + m;
|
|
||||||
var displayTime = displayHour + ':' + (m < 10 ? '0' : '') + m + ' ' + displayAmpm;
|
|
||||||
TIME_SLOTS.push({ time: timeStr, display: displayTime });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var DAYS = [
|
|
||||||
{ value: 0, name: 'Monday' },
|
|
||||||
{ value: 1, name: 'Tuesday' },
|
|
||||||
{ value: 2, name: 'Wednesday' },
|
|
||||||
{ value: 3, name: 'Thursday' },
|
|
||||||
{ value: 4, name: 'Friday' },
|
|
||||||
{ value: 5, name: 'Saturday' },
|
|
||||||
{ value: 6, name: 'Sunday' }
|
|
||||||
];
|
|
||||||
|
|
||||||
// Store selected slots: {day: [time, time, ...]}
|
|
||||||
var selectedSlots = {};
|
|
||||||
|
|
||||||
function renderDisponibilityGrid() {
|
|
||||||
var grid = document.getElementById('disponibilities-grid');
|
|
||||||
grid.innerHTML = '<div style="margin-bottom: 10px;"><strong>Click time blocks to select your available hours</strong></div>';
|
|
||||||
|
|
||||||
var container = document.createElement('div');
|
|
||||||
container.className = 'disponibility-grid';
|
|
||||||
|
|
||||||
DAYS.forEach(function(day) {
|
|
||||||
var dayRow = document.createElement('div');
|
|
||||||
dayRow.className = 'disponibility-day-row';
|
|
||||||
|
|
||||||
var dayLabel = document.createElement('div');
|
|
||||||
dayLabel.className = 'disponibility-day-label';
|
|
||||||
dayLabel.textContent = day.name;
|
|
||||||
dayRow.appendChild(dayLabel);
|
|
||||||
|
|
||||||
var timeBlocks = document.createElement('div');
|
|
||||||
timeBlocks.className = 'disponibility-time-blocks';
|
|
||||||
|
|
||||||
TIME_SLOTS.forEach(function(slot) {
|
|
||||||
var block = document.createElement('div');
|
|
||||||
block.className = 'disponibility-time-block';
|
|
||||||
block.dataset.day = day.value;
|
|
||||||
block.dataset.time = slot.time;
|
|
||||||
block.textContent = slot.display;
|
|
||||||
block.onclick = function() {
|
|
||||||
toggleSlot(day.value, slot.time, block);
|
|
||||||
};
|
|
||||||
timeBlocks.appendChild(block);
|
|
||||||
});
|
|
||||||
|
|
||||||
dayRow.appendChild(timeBlocks);
|
|
||||||
container.appendChild(dayRow);
|
|
||||||
});
|
|
||||||
|
|
||||||
grid.appendChild(container);
|
|
||||||
loadMyDisponibilities();
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleSlot(day, time, element) {
|
|
||||||
if (!selectedSlots[day]) selectedSlots[day] = [];
|
|
||||||
|
|
||||||
var index = selectedSlots[day].indexOf(time);
|
|
||||||
if (index > -1) {
|
|
||||||
selectedSlots[day].splice(index, 1);
|
|
||||||
element.classList.remove('selected');
|
|
||||||
} else {
|
|
||||||
selectedSlots[day].push(time);
|
|
||||||
element.classList.add('selected');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadMyDisponibilities() {
|
|
||||||
fetch('{{ url_for("users.get_my_disponibilities") }}')
|
|
||||||
.then(function(response) { return response.json(); })
|
|
||||||
.then(function(data) {
|
|
||||||
selectedSlots = {};
|
|
||||||
|
|
||||||
for (var day in data) {
|
|
||||||
var slots = data[day];
|
|
||||||
slots.forEach(function(slot) {
|
|
||||||
selectedSlots[day] = selectedSlots[day] || [];
|
|
||||||
selectedSlots[day].push(slot.start_time);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelectorAll('.disponibility-time-block').forEach(function(block) {
|
|
||||||
var day = block.dataset.day;
|
|
||||||
var time = block.dataset.time;
|
|
||||||
if (selectedSlots[day] && selectedSlots[day].indexOf(time) > -1) {
|
|
||||||
block.classList.add('selected');
|
|
||||||
} else {
|
|
||||||
block.classList.remove('selected');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(function(error) {
|
|
||||||
console.error('Error loading disponibilities:', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveDisponibilities() {
|
|
||||||
var slots = [];
|
|
||||||
for (var day in selectedSlots) {
|
|
||||||
selectedSlots[day].forEach(function(time) {
|
|
||||||
slots.push({ day_of_week: parseInt(day), start_time: time });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch('{{ url_for("users.add_disponibilities_bulk") }}', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ slots: slots })
|
|
||||||
})
|
|
||||||
.then(function(response) { return response.json(); })
|
|
||||||
.then(function(data) {
|
|
||||||
if (data.success) {
|
|
||||||
var msg = document.createElement('div');
|
|
||||||
msg.className = 'alert alert-success';
|
|
||||||
msg.style.marginTop = '10px';
|
|
||||||
msg.innerHTML = '<i class="fas fa-check"></i> Disponibilities saved successfully!';
|
|
||||||
document.getElementById('disponibilities-grid').appendChild(msg);
|
|
||||||
setTimeout(function() { msg.remove(); }, 3000);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function(error) {
|
|
||||||
console.error('Error saving disponibilities:', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearDisponibilities() {
|
|
||||||
if (!confirm('Are you sure you want to clear all your disponibilities?')) return;
|
|
||||||
|
|
||||||
fetch('{{ url_for("users.clear_disponibilities") }}', {
|
|
||||||
method: 'POST'
|
|
||||||
})
|
|
||||||
.then(function(response) { return response.json(); })
|
|
||||||
.then(function(data) {
|
|
||||||
if (data.success) {
|
|
||||||
selectedSlots = {};
|
|
||||||
document.querySelectorAll('.disponibility-time-block').forEach(function(block) {
|
|
||||||
block.classList.remove('selected');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -145,6 +145,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Player Disponibilities Card -->
|
||||||
|
{% if user.role == 'player' %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3><i class="fas fa-clock"></i> My Disponibilities</h3>
|
||||||
|
<p class="text-muted small">Your available time blocks for matches (5pm to 12am). Green = selected, Gray = available to select.</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="disponibilities-grid">
|
||||||
|
<p class="text-muted">Loading...</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions mt-3">
|
||||||
|
<button type="button" class="btn btn-primary" onclick="saveDisponibilities()">
|
||||||
|
<i class="fas fa-save"></i> Save Disponibilities
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="clearDisponibilities()">
|
||||||
|
<i class="fas fa-trash"></i> Clear All
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Coach Availability Card -->
|
||||||
|
{% if user.role == 'coach' %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3><i class="fas fa-clock"></i> My Availability</h3>
|
||||||
|
<p class="text-muted small">Select time slots when you're available for One on One sessions (8am to 10pm).</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="availability-grid" id="availability-grid">
|
||||||
|
<p class="text-muted">Loading availability grid...</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions mt-3">
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="clearAllAvailability()">
|
||||||
|
<i class="fas fa-trash"></i> Clear All
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- Contracts Card -->
|
<!-- Contracts Card -->
|
||||||
{% if user.role == 'player' %}
|
{% if user.role == 'player' %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@@ -182,3 +225,366 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{% if user.role == 'player' %}
|
||||||
|
<script>
|
||||||
|
// Generate time slots from 5pm (17:00) to 12am (24:00)
|
||||||
|
var TIME_SLOTS = [];
|
||||||
|
for (var h = 17; h <= 24; h++) {
|
||||||
|
for (var m = 0; m < 60; m += 30) {
|
||||||
|
if (h === 24 && m > 0) continue;
|
||||||
|
var displayHour;
|
||||||
|
var displayAmpm;
|
||||||
|
if (h === 24) {
|
||||||
|
displayHour = 12;
|
||||||
|
displayAmpm = 'AM';
|
||||||
|
} else if (h > 12) {
|
||||||
|
displayHour = h - 12;
|
||||||
|
displayAmpm = 'PM';
|
||||||
|
} else {
|
||||||
|
displayHour = h;
|
||||||
|
displayAmpm = 'PM';
|
||||||
|
}
|
||||||
|
var timeStr = (h < 10 ? '0' : '') + h + ':' + (m < 10 ? '0' : '') + m;
|
||||||
|
var displayTime = displayHour + ':' + (m < 10 ? '0' : '') + m + ' ' + displayAmpm;
|
||||||
|
TIME_SLOTS.push({ time: timeStr, display: displayTime });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var DAYS = [
|
||||||
|
{ value: 0, name: 'Monday' },
|
||||||
|
{ value: 1, name: 'Tuesday' },
|
||||||
|
{ value: 2, name: 'Wednesday' },
|
||||||
|
{ value: 3, name: 'Thursday' },
|
||||||
|
{ value: 4, name: 'Friday' },
|
||||||
|
{ value: 5, name: 'Saturday' },
|
||||||
|
{ value: 6, name: 'Sunday' }
|
||||||
|
];
|
||||||
|
|
||||||
|
var selectedSlots = {};
|
||||||
|
|
||||||
|
function renderDisponibilityGrid() {
|
||||||
|
var grid = document.getElementById('disponibilities-grid');
|
||||||
|
grid.innerHTML = '<div style="margin-bottom: 10px;"><strong>Click time blocks to select your available hours</strong></div>';
|
||||||
|
|
||||||
|
var container = document.createElement('div');
|
||||||
|
container.className = 'disponibility-grid';
|
||||||
|
|
||||||
|
DAYS.forEach(function(day) {
|
||||||
|
var dayRow = document.createElement('div');
|
||||||
|
dayRow.className = 'disponibility-day-row';
|
||||||
|
|
||||||
|
var dayLabel = document.createElement('div');
|
||||||
|
dayLabel.className = 'disponibility-day-label';
|
||||||
|
dayLabel.textContent = day.name;
|
||||||
|
dayRow.appendChild(dayLabel);
|
||||||
|
|
||||||
|
var timeBlocks = document.createElement('div');
|
||||||
|
timeBlocks.className = 'disponibility-time-blocks';
|
||||||
|
|
||||||
|
TIME_SLOTS.forEach(function(slot) {
|
||||||
|
var block = document.createElement('div');
|
||||||
|
block.className = 'disponibility-time-block';
|
||||||
|
block.dataset.day = day.value;
|
||||||
|
block.dataset.time = slot.time;
|
||||||
|
block.textContent = slot.display;
|
||||||
|
block.onclick = function() {
|
||||||
|
toggleSlot(day.value, slot.time, block);
|
||||||
|
};
|
||||||
|
timeBlocks.appendChild(block);
|
||||||
|
});
|
||||||
|
|
||||||
|
dayRow.appendChild(timeBlocks);
|
||||||
|
container.appendChild(dayRow);
|
||||||
|
});
|
||||||
|
|
||||||
|
grid.appendChild(container);
|
||||||
|
loadMyDisponibilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSlot(day, time, element) {
|
||||||
|
if (!selectedSlots[day]) selectedSlots[day] = [];
|
||||||
|
|
||||||
|
var index = selectedSlots[day].indexOf(time);
|
||||||
|
if (index > -1) {
|
||||||
|
selectedSlots[day].splice(index, 1);
|
||||||
|
element.classList.remove('selected');
|
||||||
|
} else {
|
||||||
|
selectedSlots[day].push(time);
|
||||||
|
element.classList.add('selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMyDisponibilities() {
|
||||||
|
fetch('{{ url_for("users.get_my_disponibilities") }}')
|
||||||
|
.then(function(response) { return response.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
selectedSlots = {};
|
||||||
|
|
||||||
|
for (var day in data) {
|
||||||
|
var slots = data[day];
|
||||||
|
slots.forEach(function(slot) {
|
||||||
|
selectedSlots[day] = selectedSlots[day] || [];
|
||||||
|
selectedSlots[day].push(slot.start_time);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.disponibility-time-block').forEach(function(block) {
|
||||||
|
var day = block.dataset.day;
|
||||||
|
var time = block.dataset.time;
|
||||||
|
if (selectedSlots[day] && selectedSlots[day].indexOf(time) > -1) {
|
||||||
|
block.classList.add('selected');
|
||||||
|
} else {
|
||||||
|
block.classList.remove('selected');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.error('Error loading disponibilities:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDisponibilities() {
|
||||||
|
var slots = [];
|
||||||
|
for (var day in selectedSlots) {
|
||||||
|
selectedSlots[day].forEach(function(time) {
|
||||||
|
slots.push({ day_of_week: parseInt(day), start_time: time });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('{{ url_for("users.add_disponibilities_bulk") }}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ slots: slots })
|
||||||
|
})
|
||||||
|
.then(function(response) { return response.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.success) {
|
||||||
|
var msg = document.createElement('div');
|
||||||
|
msg.className = 'alert alert-success';
|
||||||
|
msg.style.marginTop = '10px';
|
||||||
|
msg.innerHTML = '<i class="fas fa-check"></i> Disponibilities saved successfully!';
|
||||||
|
document.getElementById('disponibilities-grid').appendChild(msg);
|
||||||
|
setTimeout(function() { msg.remove(); }, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.error('Error saving disponibilities:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDisponibilities() {
|
||||||
|
if (!confirm('Are you sure you want to clear all your disponibilities?')) return;
|
||||||
|
|
||||||
|
fetch('{{ url_for("users.clear_disponibilities") }}', {
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
.then(function(response) { return response.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.success) {
|
||||||
|
selectedSlots = {};
|
||||||
|
document.querySelectorAll('.disponibility-time-block').forEach(function(block) {
|
||||||
|
block.classList.remove('selected');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
renderDisponibilityGrid();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if user.role == 'coach' %}
|
||||||
|
<style>
|
||||||
|
.availability-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-column {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-header {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-slot {
|
||||||
|
padding: 6px 8px;
|
||||||
|
margin: 4px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--transition);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-slot:hover {
|
||||||
|
background: var(--primary-light);
|
||||||
|
border-color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-slot.selected {
|
||||||
|
background: var(--primary);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--primary-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-slot.selected:hover {
|
||||||
|
background: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.availability-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.availability-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
const COACH_TIME_SLOTS = [];
|
||||||
|
for (let h = 8; h <= 22; h++) {
|
||||||
|
for (let m = 0; m < 60; m += 30) {
|
||||||
|
const timeStr = (h < 10 ? '0' : '') + h + ':' + (m < 10 ? '0' : '') + m;
|
||||||
|
const displayHour = h > 12 ? h - 12 : h;
|
||||||
|
const displayAmpm = h >= 12 ? 'PM' : 'AM';
|
||||||
|
const displayTime = displayHour + ':' + (m < 10 ? '0' : '') + m + ' ' + displayAmpm;
|
||||||
|
COACH_TIME_SLOTS.push({ time: timeStr, display: displayTime });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const COACH_DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||||
|
|
||||||
|
let coachSelectedSlots = {};
|
||||||
|
|
||||||
|
function loadExistingAvailability() {
|
||||||
|
{% for av in coach_availability %}
|
||||||
|
if (!coachSelectedSlots[{{ av.day_of_week }}]) {
|
||||||
|
coachSelectedSlots[{{ av.day_of_week }}] = [];
|
||||||
|
}
|
||||||
|
coachSelectedSlots[{{ av.day_of_week }}].push('{{ av.start_time.strftime('%H:%M') }}');
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCoachGrid() {
|
||||||
|
const grid = document.getElementById('availability-grid');
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
COACH_DAYS.forEach((day, dayIndex) => {
|
||||||
|
html += '<div class="day-column">';
|
||||||
|
html += '<div class="day-header">' + day.substring(0, 3) + '</div>';
|
||||||
|
|
||||||
|
COACH_TIME_SLOTS.forEach(slot => {
|
||||||
|
const isSelected = coachSelectedSlots[dayIndex] && coachSelectedSlots[dayIndex].includes(slot.time);
|
||||||
|
const cssClass = isSelected ? 'time-slot selected' : 'time-slot';
|
||||||
|
html += '<div class="' + cssClass + '" data-day="' + dayIndex + '" data-time="' + slot.time + '" onclick="toggleCoachSlot(' + dayIndex + ', \'' + slot.time + '\', this)">' + slot.display + '</div>';
|
||||||
|
});
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
});
|
||||||
|
|
||||||
|
grid.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCoachSlot(dayOfWeek, timeStr, element) {
|
||||||
|
if (!coachSelectedSlots[dayOfWeek]) {
|
||||||
|
coachSelectedSlots[dayOfWeek] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = coachSelectedSlots[dayOfWeek].indexOf(timeStr);
|
||||||
|
if (index === -1) {
|
||||||
|
coachSelectedSlots[dayOfWeek].push(timeStr);
|
||||||
|
element.classList.add('selected');
|
||||||
|
} else {
|
||||||
|
coachSelectedSlots[dayOfWeek].splice(index, 1);
|
||||||
|
element.classList.remove('selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveCoachAvailability() {
|
||||||
|
const slots = [];
|
||||||
|
for (let day in coachSelectedSlots) {
|
||||||
|
coachSelectedSlots[day].forEach(time => {
|
||||||
|
slots.push({ day_of_week: parseInt(day), start_time: time });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('{{ url_for("users.manage_coach_availability") }}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ slots: slots })
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
var msg = document.createElement('div');
|
||||||
|
msg.className = 'alert alert-success';
|
||||||
|
msg.style.marginTop = '10px';
|
||||||
|
msg.innerHTML = '<i class="fas fa-check"></i> Availability saved!';
|
||||||
|
document.getElementById('availability-grid').parentElement.appendChild(msg);
|
||||||
|
setTimeout(function() { msg.remove(); }, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.error('Save error:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAllAvailability() {
|
||||||
|
if (!confirm('Are you sure you want to clear all your availability slots?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('{{ url_for("users.clear_coach_availability") }}', { method: 'POST' })
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
coachSelectedSlots = {};
|
||||||
|
renderCoachGrid();
|
||||||
|
var msg = document.createElement('div');
|
||||||
|
msg.className = 'alert alert-success';
|
||||||
|
msg.style.marginTop = '10px';
|
||||||
|
msg.innerHTML = '<i class="fas fa-check"></i> Availability cleared!';
|
||||||
|
document.getElementById('availability-grid').parentElement.appendChild(msg);
|
||||||
|
setTimeout(function() { msg.remove(); }, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let coachSaveTimeout;
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
if (e.target.classList.contains('time-slot')) {
|
||||||
|
clearTimeout(coachSaveTimeout);
|
||||||
|
coachSaveTimeout = setTimeout(saveCoachAvailability, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
loadExistingAvailability();
|
||||||
|
renderCoachGrid();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user