"""When people are free. Two calendars that share a shape without sharing a purpose: a player's weekly availability blocks, and a coach's bookable slots for one-on-one sessions. """ from datetime import datetime, timedelta from flask import flash, jsonify, redirect, render_template, request, url_for from flask_babel import gettext as _ from flask_login import current_user, login_required from app.api import json_endpoint from app.extensions import db from app.models import Coach, CoachAvailability, PlayerDisponibility, User from app.routes.users.blueprint import users_bp DAY_NAMES = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] def add_30_minutes(t): return (datetime.combine(datetime.today(), t) + timedelta(minutes=30)).time() @users_bp.route('/disponibilities') @json_endpoint @login_required def get_disponibilities(): """API endpoint to get all player disponibilities for scheduling.""" if not current_user.can_manage_teams() and not current_user.can_schedule_matches(): return jsonify({'error': 'Unauthorized'}), 403 players = ( User.query.filter_by(role='player', is_active_account=True).order_by(User.username).all() ) result = {} for player in players: disponibilities = list(player.disponibilities) result[player.id] = { 'username': player.username, 'disponibilities': [ { 'id': d.id, 'day_of_week': d.day_of_week, 'day_name': DAY_NAMES[d.day_of_week], 'start_time': d.start_time.strftime('%H:%M'), 'end_time': d.end_time.strftime('%H:%M'), } for d in disponibilities ], } return jsonify(result) @users_bp.route('/disponibilities/my') @json_endpoint @login_required def get_my_disponibilities(): """API endpoint for players to get their own disponibilities.""" disponibilities = PlayerDisponibility.query.filter_by(player_id=current_user.id).all() result = {} for d in disponibilities: day = d.day_of_week if day not in result: result[day] = [] result[day].append( { 'id': d.id, 'day_of_week': d.day_of_week, 'day_name': DAY_NAMES[d.day_of_week], 'start_time': d.start_time.strftime('%H:%M'), 'end_time': d.end_time.strftime('%H:%M'), } ) return jsonify(result) @users_bp.route('/disponibilities/add', methods=['POST']) @json_endpoint @login_required def add_disponibility(): """Add a disponibility block for the current player.""" day_of_week = request.form.get('day_of_week', type=int) start_time_str = request.form.get('start_time') if day_of_week is None or day_of_week < 0 or day_of_week > 6: return jsonify({'error': 'Invalid day of week'}), 400 try: start_time = datetime.strptime(start_time_str, '%H:%M').time() except (ValueError, TypeError): return jsonify({'error': 'Invalid time format'}), 400 end_time = add_30_minutes(start_time) disponibility = PlayerDisponibility( player_id=current_user.id, day_of_week=day_of_week, start_time=start_time, end_time=end_time, ) db.session.add(disponibility) db.session.commit() return jsonify( { 'id': disponibility.id, 'day_of_week': disponibility.day_of_week, 'day_name': DAY_NAMES[disponibility.day_of_week], 'start_time': disponibility.start_time.strftime('%H:%M'), 'end_time': disponibility.end_time.strftime('%H:%M'), } ) @users_bp.route('/disponibilities/add_bulk', methods=['POST']) @json_endpoint @login_required def add_disponibilities_bulk(): """Add multiple disponibility blocks at once.""" data = request.get_json() slots = data.get('slots', []) created = [] for slot in slots: day_of_week = slot.get('day_of_week') start_time_str = slot.get('start_time') if day_of_week is None or day_of_week < 0 or day_of_week > 6: continue try: start_time = datetime.strptime(start_time_str, '%H:%M').time() except (ValueError, TypeError): continue end_time = add_30_minutes(start_time) existing = PlayerDisponibility.query.filter_by( player_id=current_user.id, day_of_week=day_of_week, start_time=start_time, ).first() if not existing: disponibility = PlayerDisponibility( player_id=current_user.id, day_of_week=day_of_week, start_time=start_time, end_time=end_time, ) db.session.add(disponibility) db.session.flush() created.append( { 'id': disponibility.id, 'day_of_week': disponibility.day_of_week, 'day_name': DAY_NAMES[disponibility.day_of_week], 'start_time': disponibility.start_time.strftime('%H:%M'), } ) db.session.commit() return jsonify({'success': True, 'created': created}) @users_bp.route('/disponibilities/clear', methods=['POST']) @json_endpoint @login_required def clear_disponibilities(): """Clear all disponibilities for the current player.""" PlayerDisponibility.query.filter_by(player_id=current_user.id).delete() db.session.commit() return jsonify({'success': True}) @users_bp.route('/disponibilities//delete', methods=['POST']) @json_endpoint @login_required def delete_disponibility(disponibility_id): """Delete a disponibility block.""" disponibility = PlayerDisponibility.query.get_or_404(disponibility_id) if disponibility.player_id != current_user.id: return jsonify({'error': 'Unauthorized'}), 403 db.session.delete(disponibility) db.session.commit() return jsonify({'success': True}) @users_bp.route('/coach-availability', methods=['GET', 'POST']) @json_endpoint @login_required def manage_coach_availability(): """Manage coach availability for One on One sessions.""" if not isinstance(current_user, Coach): flash(_('Only coaches can manage availability.'), 'danger') return redirect(url_for('main.dashboard')) if request.method == 'POST': data = request.get_json() slots = data.get('slots', []) if data else [] # Clear existing availability CoachAvailability.query.filter_by(coach_id=current_user.id).delete() # Add new slots for slot in slots: day_of_week = slot.get('day_of_week') start_time_str = slot.get('start_time') if day_of_week is None or day_of_week < 0 or day_of_week > 6: continue try: start_time = datetime.strptime(start_time_str, '%H:%M').time() end_time = ( datetime.combine(datetime.today(), start_time) + timedelta(minutes=30) ).time() except (ValueError, TypeError): continue availability = CoachAvailability( coach_id=current_user.id, day_of_week=day_of_week, start_time=start_time, end_time=end_time, ) db.session.add(availability) db.session.commit() return jsonify({'success': True}) existing_availability = CoachAvailability.query.filter_by( coach_id=current_user.id, ).all() return render_template( 'pages/coach_availability.html', existing_availability=existing_availability ) @users_bp.route('/coach-availability/clear', methods=['POST']) @json_endpoint @login_required def clear_coach_availability(): """Clear all coach availability slots.""" if not isinstance(current_user, Coach): return jsonify({'error': 'Unauthorized'}), 403 CoachAvailability.query.filter_by(coach_id=current_user.id).delete() db.session.commit() return jsonify({'success': True})