diff --git a/__pycache__/models.cpython-313.pyc b/__pycache__/models.cpython-313.pyc index 4fae20e..42c0d3c 100644 Binary files a/__pycache__/models.cpython-313.pyc and b/__pycache__/models.cpython-313.pyc differ diff --git a/instance/team_tryouts.db b/instance/team_tryouts.db index dff8222..d0243f9 100644 Binary files a/instance/team_tryouts.db and b/instance/team_tryouts.db differ diff --git a/models.py b/models.py index d2863de..e076b32 100644 --- a/models.py +++ b/models.py @@ -156,8 +156,9 @@ class User(UserMixin, db.Model): def can_manage_this_tryout(self, tryout): """Check if user can manage a specific tryout. - Presidents can manage all tryouts. Managers can manage their own tryouts. - Coaches can manage tryouts targeting their coached team. + Presidents can manage all tryouts. Managers can manage their own tryouts + or tryouts where they are assigned as manager. Coaches can manage tryouts + targeting their coached team or where they are assigned as coach. Args: tryout: The Tryout object to check permissions for. @@ -167,12 +168,14 @@ class User(UserMixin, db.Model): """ if self.role == 'president': return True - if self.role == 'manager' and tryout.created_by == self.id: + if self.role == 'manager' and (tryout.created_by == self.id or tryout.manager_id == self.id): return True if self.role == 'coach': org_team = OrgTeam.query.filter_by(coach_id=self.id).first() if org_team and tryout.target_org_team_id == org_team.id: return True + if tryout.coach_id == self.id: + return True return False def can_manage_this_org_team(self, org_team): @@ -392,6 +395,8 @@ class Tryout(db.Model): max_players: Maximum number of players allowed. created_by: Foreign key to the creating manager/president. target_org_team_id: Foreign key to target organization team. + manager_id: Foreign key to the assigned manager. + coach_id: Foreign key to the assigned coach. created_at: Timestamp of creation. """ __tablename__ = 'tryouts' @@ -405,9 +410,13 @@ class Tryout(db.Model): max_players = db.Column(db.Integer, nullable=True) created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) target_org_team_id = db.Column(db.Integer, db.ForeignKey('org_teams.id'), nullable=True) + manager_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) + coach_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) - creator = db.relationship('User', backref='created_tryouts') + creator = db.relationship('User', foreign_keys=[created_by], backref='created_tryouts') + manager = db.relationship('User', foreign_keys=[manager_id], backref='managed_tryouts') + coach = db.relationship('User', foreign_keys=[coach_id], backref='coached_tryouts') registrations = db.relationship('TryoutRegistration', backref='tryout', lazy='dynamic') evaluations = db.relationship('Evaluation', backref='tryout', lazy='dynamic') teams = db.relationship('Team', backref='tryout', lazy='dynamic') diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index a0e4776..60e5fbd 100644 Binary files a/routes/__pycache__/main.cpython-313.pyc and b/routes/__pycache__/main.cpython-313.pyc differ diff --git a/routes/__pycache__/matches.cpython-313.pyc b/routes/__pycache__/matches.cpython-313.pyc index a874955..c44c888 100644 Binary files a/routes/__pycache__/matches.cpython-313.pyc and b/routes/__pycache__/matches.cpython-313.pyc differ diff --git a/routes/__pycache__/tryouts.cpython-313.pyc b/routes/__pycache__/tryouts.cpython-313.pyc index 5a80b27..1515b63 100644 Binary files a/routes/__pycache__/tryouts.cpython-313.pyc and b/routes/__pycache__/tryouts.cpython-313.pyc differ diff --git a/routes/__pycache__/users.cpython-313.pyc b/routes/__pycache__/users.cpython-313.pyc index beafbbe..bcaa8db 100644 Binary files a/routes/__pycache__/users.cpython-313.pyc and b/routes/__pycache__/users.cpython-313.pyc differ diff --git a/routes/main.py b/routes/main.py index aa53cc5..43ee72c 100644 --- a/routes/main.py +++ b/routes/main.py @@ -52,12 +52,24 @@ def dashboard(): stats['completed_tryouts'] = Tryout.query.filter_by(status='completed').count() stats['recent_users'] = User.query.order_by(User.created_at.desc()).limit(10).all() stats['recent_tryouts'] = Tryout.query.order_by(Tryout.created_at.desc()).limit(10).all() + today = date.today() + stats['upcoming_matches'] = Match.query.filter( + Match.status == 'scheduled', + Match.date >= today + ).order_by(Match.date, Match.start_time).limit(5).all() elif user.role == 'manager': stats['total_tryouts'] = Tryout.query.filter_by(created_by=user.id).count() stats['active_tryouts'] = Tryout.query.filter_by(created_by=user.id, status='in_progress').count() stats['total_evaluations'] = Evaluation.query.filter_by(evaluator_id=user.id).count() stats['my_tryouts'] = Tryout.query.filter_by(created_by=user.id).order_by(Tryout.date.desc()).limit(5).all() + today = date.today() + manager_tryout_ids = [t.id for t in Tryout.query.filter_by(created_by=user.id).all()] + stats['upcoming_matches'] = Match.query.filter( + Match.tryout_id.in_(manager_tryout_ids), + Match.status == 'scheduled', + Match.date >= today + ).order_by(Match.date, Match.start_time).limit(5).all() if manager_tryout_ids else [] elif user.role == 'coach': stats['my_evaluations'] = Evaluation.query.filter_by(evaluator_id=user.id).count() @@ -67,54 +79,66 @@ def dashboard(): evaluated_player_ids = [e.player_id for e in Evaluation.query.filter_by(evaluator_id=user.id).all()] stats['pending_evaluations'] = len(set(registered_player_ids) - set(evaluated_player_ids)) stats['my_recent_evaluations'] = Evaluation.query.filter_by(evaluator_id=user.id).order_by(Evaluation.created_at.desc()).limit(10).all() + today = date.today() + org_team = OrgTeam.query.filter_by(coach_id=user.id).first() + coach_tryout_ids = [t.id for t in Tryout.query.filter_by(target_org_team_id=org_team.id).all()] if org_team else [] + stats['upcoming_matches'] = Match.query.filter( + Match.tryout_id.in_(coach_tryout_ids), + Match.status == 'scheduled', + Match.date >= today + ).order_by(Match.date, Match.start_time).limit(5).all() if coach_tryout_ids else [] elif user.role == 'player': stats['my_tryouts'] = TryoutRegistration.query.filter_by(player_id=user.id).count() stats['my_registrations'] = TryoutRegistration.query.filter_by(player_id=user.id).order_by(TryoutRegistration.registered_at.desc()).limit(5).all() - # Get next match for each tryout the player is in + # Get upcoming matches for the player today = date.today() next_matches = [] - for reg in stats['my_registrations']: - tryout = reg.tryout - # Find matches where player participates (team membership or direct participant) - player_teams = Team.query.join(TeamMember).filter( - Team.tryout_id == tryout.id, - TeamMember.player_id == user.id - ).all() + + # Get all tryouts the player is registered for (not just the 5 most recent) + all_registrations = TryoutRegistration.query.filter_by(player_id=user.id).all() + registered_tryout_ids = [r.tryout_id for r in all_registrations] + + # Get all matches where player is a participant (any match type) + player_participant_matches = MatchParticipant.query.filter_by(player_id=user.id).all() + player_match_ids = [p.match_id for p in player_participant_matches] + + # Get all team memberships for this player + player_team_memberships = TeamMember.query.filter_by(player_id=user.id).all() + player_team_ids = [tm.team_id for tm in player_team_memberships] + + # Find all scheduled matches in registered tryouts + upcoming_matches = Match.query.filter( + Match.tryout_id.in_(registered_tryout_ids), + Match.status == 'scheduled', + Match.date >= today + ).order_by(Match.date, Match.start_time).all() + + for match in upcoming_matches: + is_participant = False + team = None - # Get matches for this tryout that include the player - tryout_matches = Match.query.filter( - Match.tryout_id == tryout.id, - Match.status == 'scheduled' - ).order_by(Match.date, Match.start_time).all() + if match.match_type == 'team_vs_team': + # Check if player is on either team + if match.team1_id in player_team_ids: + is_participant = True + team = next((tm for tm in player_team_memberships if tm.team_id == match.team1_id), None) + elif match.team2_id in player_team_ids: + is_participant = True + team = next((tm for tm in player_team_memberships if tm.team_id == match.team2_id), None) + else: + # For player_vs_player and player_scrim, check MatchParticipant + if match.id in player_match_ids: + is_participant = True - for match in tryout_matches: - # Check if player is in this match - is_participant = False - if match.match_type == 'team_vs_team': - # Check if player is on team1 or team2 - if match.team1_id in [t.id for t in player_teams] or match.team2_id in [t.id for t in player_teams]: - is_participant = True - else: - # Check if player is in match participants - participant = MatchParticipant.query.filter_by( - match_id=match.id, - player_id=user.id - ).first() - if participant: - is_participant = True - - if is_participant: - # Check if match is upcoming - match_date = match.date - if match_date >= today: - next_matches.append({ - 'tryout': tryout, - 'match': match, - 'team': player_teams[0] if player_teams else None - }) - break # Only get the next match per tryout + if is_participant: + tryout = match.tryout + next_matches.append({ + 'tryout': tryout, + 'match': match, + 'team': team.team if team else None + }) stats['next_matches'] = next_matches diff --git a/routes/matches.py b/routes/matches.py index 10b3b38..291f01b 100644 --- a/routes/matches.py +++ b/routes/matches.py @@ -309,13 +309,13 @@ def create_match(tryout_id): # Start time is now mandatory if not start_time_str: flash('Start time is required. Please select a time slot.', 'danger') - return render_template('pages/create_match.html', tryout=tryout, teams=teams, all_players=all_players) + return render_template('pages/match_form.html', tryout=tryout, teams=teams, all_players=all_players) try: date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else tryout.date except (ValueError, TypeError): flash('Invalid date format.', 'danger') - return render_template('pages/create_match.html', tryout=tryout, teams=teams, all_players=all_players) + return render_template('pages/match_form.html', tryout=tryout, teams=teams, all_players=all_players) start_time = None end_time = None @@ -331,7 +331,7 @@ def create_match(tryout_id): end_time = end_dt.time() except ValueError: flash('Invalid time format.', 'danger') - return render_template('pages/create_match.html', tryout=tryout, teams=teams, all_players=all_players) + return render_template('pages/match_form.html', tryout=tryout, teams=teams, all_players=all_players) match = Match( tryout_id=tryout_id, @@ -425,7 +425,7 @@ def create_match(tryout_id): flash('Match scheduled successfully!', 'success') return redirect(url_for('tryouts.view_tryout', tryout_id=tryout_id)) - return render_template('pages/create_match.html', tryout=tryout, teams=teams, all_players=all_players) + return render_template('pages/match_form.html', tryout=tryout, teams=teams, all_players=all_players) @matches_bp.route('//edit', methods=['GET', 'POST']) @@ -472,12 +472,12 @@ def edit_match(match_id): match.date = datetime.strptime(date_str, '%Y-%m-%d').date() except (ValueError, TypeError): flash('Invalid date format.', 'danger') - return render_template('pages/edit_match.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids) + return render_template('pages/match_form.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids) # Start time is now mandatory if not start_time_str: flash('Start time is required. Please select a time slot.', 'danger') - return render_template('pages/edit_match.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids) + return render_template('pages/match_form.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids) try: match.start_time = datetime.strptime(start_time_str, '%H:%M').time() @@ -578,7 +578,7 @@ def edit_match(match_id): flash('Match updated successfully!', 'success') return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id)) - return render_template('pages/edit_match.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids, team1_player_ids=team1_player_ids, team2_player_ids=team2_player_ids) + return render_template('pages/match_form.html', match=match, tryout=tryout, teams=teams, all_players=all_players, current_player_ids=current_player_ids, team1_player_ids=team1_player_ids, team2_player_ids=team2_player_ids) @matches_bp.route('//delete', methods=['POST']) diff --git a/routes/tryouts.py b/routes/tryouts.py index 9bbc819..c9fa812 100644 --- a/routes/tryouts.py +++ b/routes/tryouts.py @@ -73,6 +73,8 @@ def create_tryout(): return redirect(url_for('tryouts.list_tryouts')) org_teams = OrgTeam.query.order_by(OrgTeam.name).all() + managers = User.query.filter_by(role='manager', is_active_account=True).order_by(User.full_name).all() + coaches = User.query.filter_by(role='coach', is_active_account=True).order_by(User.full_name).all() if request.method == 'POST': title = request.form.get('title') @@ -82,12 +84,14 @@ def create_tryout(): location = request.form.get('location') max_players = request.form.get('max_players') target_org_team_id = request.form.get('target_org_team_id') + manager_id = request.form.get('manager_id') + coach_id = request.form.get('coach_id') try: date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() except (ValueError, TypeError): flash('Invalid date format.', 'danger') - return render_template('pages/create_tryout.html', org_teams=org_teams) + return render_template('pages/tryout_form.html', tryout=None, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES) tryout = Tryout( title=title, @@ -98,14 +102,16 @@ def create_tryout(): max_players=int(max_players) if max_players else None, created_by=current_user.id, status='upcoming', - target_org_team_id=int(target_org_team_id) if target_org_team_id else None + target_org_team_id=int(target_org_team_id) if target_org_team_id else None, + manager_id=int(manager_id) if manager_id else None, + coach_id=int(coach_id) if coach_id else None ) db.session.add(tryout) db.session.commit() flash('Tryout created successfully!', 'success') return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id)) - return render_template('pages/create_tryout.html', org_teams=org_teams, esport_games=ESPORT_GAMES) + return render_template('pages/tryout_form.html', tryout=None, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES) @tryouts_bp.route('//edit', methods=['GET', 'POST']) @@ -132,6 +138,8 @@ def edit_tryout(tryout_id): return redirect(url_for('tryouts.list_tryouts')) org_teams = OrgTeam.query.order_by(OrgTeam.name).all() + managers = User.query.filter_by(role='manager', is_active_account=True).order_by(User.full_name).all() + coaches = User.query.filter_by(role='coach', is_active_account=True).order_by(User.full_name).all() if request.method == 'POST': title = request.form.get('title') @@ -141,12 +149,14 @@ def edit_tryout(tryout_id): location = request.form.get('location') max_players = request.form.get('max_players') target_org_team_id = request.form.get('target_org_team_id') + manager_id = request.form.get('manager_id') + coach_id = request.form.get('coach_id') try: date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() except (ValueError, TypeError): flash('Invalid date format.', 'danger') - return render_template('pages/edit_tryout.html', tryout=tryout, org_teams=org_teams, esport_games=ESPORT_GAMES) + return render_template('pages/tryout_form.html', tryout=tryout, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES) tryout.title = title tryout.description = description @@ -155,11 +165,13 @@ def edit_tryout(tryout_id): tryout.location = location tryout.max_players = int(max_players) if max_players else None tryout.target_org_team_id = int(target_org_team_id) if target_org_team_id else None + tryout.manager_id = int(manager_id) if manager_id else None + tryout.coach_id = int(coach_id) if coach_id else None db.session.commit() flash('Tryout updated successfully!', 'success') return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id)) - return render_template('pages/edit_tryout.html', tryout=tryout, org_teams=org_teams, esport_games=ESPORT_GAMES) + return render_template('pages/tryout_form.html', tryout=tryout, org_teams=org_teams, managers=managers, coaches=coaches, esport_games=ESPORT_GAMES) @tryouts_bp.route('/') diff --git a/routes/users.py b/routes/users.py index f4c1bcf..87cf69e 100644 --- a/routes/users.py +++ b/routes/users.py @@ -1433,12 +1433,13 @@ def add_personal_note(): flash('Personal note added successfully!', 'success') return redirect(url_for('users.notes_dashboard')) - return render_template('pages/add_personal_note.html', + return render_template('pages/add_note.html', players=players, matches=matches, tryouts=tryouts, teams=teams, - org_team=org_team) + org_team=org_team, + context_type='general') @users_bp.route('/match//add-note', methods=['GET', 'POST']) @@ -1509,11 +1510,12 @@ def add_note_from_match(match_id): flash('Personal note added successfully!', 'success') return redirect(url_for('tryouts.view_tryout', tryout_id=tryout.id)) - return render_template('pages/add_note_from_match.html', + return render_template('pages/add_note.html', match=match, tryout=tryout, players=players, - team_notes=team_notes) + team_notes=team_notes, + context_type='match') @users_bp.route('/tryout//add-note', methods=['GET', 'POST']) @@ -1583,8 +1585,9 @@ def add_note_from_tryout(tryout_id): # Allow pre-selecting a player via query parameter preselected_player_id = request.args.get('player_id', type=int) - return render_template('pages/add_note_from_tryout.html', + return render_template('pages/add_note.html', tryout=tryout, players=players, team_notes=team_notes, - preselected_player_id=preselected_player_id) + preselected_player_id=preselected_player_id, + context_type='tryout') diff --git a/templates/pages/add_note.html b/templates/pages/add_note.html new file mode 100644 index 0000000..859abb9 --- /dev/null +++ b/templates/pages/add_note.html @@ -0,0 +1,152 @@ +{% extends "layouts/base.html" %} +{% block title %}Add Personal Note - TryoutPro{% endblock %} +{% block page_title %}Add Personal Note{% endblock %} +{% block breadcrumb %} + + Home / Tryouts + {% if context_type == 'tryout' %} + / {{ tryout.title }} + / Add Note + {% elif context_type == 'match' %} + / {{ tryout.tryout.title }} + / Add Note + {% else %} + / Add Note + {% endif %} + +{% endblock %} + +{% block content %} +
+
+

Add Personal Note

+ {% if context_type == 'tryout' %} +

Context: Tryout - {{ tryout.title }}

+ {% elif context_type == 'match' %} +

Context: Match - {{ match.title }}

+ {% endif %} +
+
+
+ + {% if context_type == 'tryout' %} + + {% elif context_type == 'match' %} + + {% endif %} + +
+ + +
+ +
+ + +
+ + {% if context_type != 'tryout' and context_type != 'match' %} +
+ + +
+ +
+ + +
+ +
+ + +
+ {% endif %} + + {% if team_notes %} +
+ +
+ {% for note in team_notes %} +
+ {{ note.created_at.strftime('%Y-%m-%d') }} - {{ note.coach.full_name }}: +

{{ note.content[:200] }}{% if note.content|length > 200 %}...{% endif %}

+
+ {% endfor %} +
+
+ {% endif %} + +
+ Cancel + +
+
+
+
+{% endblock %} + +{% block styles %} + +{% endblock %} \ No newline at end of file diff --git a/templates/pages/add_note_from_match.html b/templates/pages/add_note_from_match.html deleted file mode 100644 index f2eaedb..0000000 --- a/templates/pages/add_note_from_match.html +++ /dev/null @@ -1,63 +0,0 @@ -{% extends "layouts/base.html" %} -{% block title %}Add Note from Match - TryoutPro{% endblock %} -{% block page_title %}Add Note from Match{% endblock %} -{% block breadcrumb %}Home / Tryouts / {{ tryout.title }} / Add Note{% endblock %} - -{% block content %} -
-
-

Add Note for Match: {{ match.title }}

- {{ match.date.strftime('%m/%d/%Y') }} -
-
-
- - -
- - -
- -
- - -

This note will be linked to this match and visible to the selected player.

-
- -
- - - Back to Tryout - -
-
-
-
- -{% if team_notes %} -
-
-

Team Notes Reference

-
-
-
- {% for note in team_notes %} -
- - {{ note.coach.full_name if note.coach else 'Unknown Coach' }} - - {{ note.content | nl2br }} -
- {% endfor %} -
-
-
-{% endif %} -{% endblock %} \ No newline at end of file diff --git a/templates/pages/add_note_from_tryout.html b/templates/pages/add_note_from_tryout.html deleted file mode 100644 index 89bd793..0000000 --- a/templates/pages/add_note_from_tryout.html +++ /dev/null @@ -1,63 +0,0 @@ -{% extends "layouts/base.html" %} -{% block title %}Add Note from Tryout - TryoutPro{% endblock %} -{% block page_title %}Add Note from Tryout{% endblock %} -{% block breadcrumb %}Home / Tryouts / {{ tryout.title }} / Add Note{% endblock %} - -{% block content %} -
-
-

Add Note for Tryout: {{ tryout.title }}

- {{ tryout.date.strftime('%m/%d/%Y') }} -
-
-
- - -
- - -
- -
- - -

This note will be linked to this tryout and visible to the selected player.

-
- -
- - - Back to Tryout - -
-
-
-
- -{% if team_notes %} -
-
-

Team Notes Reference

-
-
-
- {% for note in team_notes %} -
- - {{ note.coach.full_name if note.coach else 'Unknown Coach' }} - - {{ note.content | nl2br }} -
- {% endfor %} -
-
-
-{% endif %} -{% endblock %} \ No newline at end of file diff --git a/templates/pages/add_personal_note.html b/templates/pages/add_personal_note.html deleted file mode 100644 index 36084c2..0000000 --- a/templates/pages/add_personal_note.html +++ /dev/null @@ -1,80 +0,0 @@ -{% extends "layouts/base.html" %} -{% block title %}Add Note - TryoutPro{% endblock %} -{% block page_title %}Add Personal Note{% endblock %} -{% block breadcrumb %}Home / My Notes / Add Note{% endblock %} - -{% block content %} -
-
-

Add Personal Note

- {% if org_team %} - {{ org_team.name }} - {% endif %} -
-
-
- - -
- - -
- -
- - -

These notes will only be visible to the selected player.

-
- -
- -

Link this note to a specific match, tryout, or team for better organization.

- -
-
- - -
-
- - -
-
- - -
-
-
- -
- - - Back to Notes - -
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/templates/pages/create_match.html b/templates/pages/create_match.html deleted file mode 100644 index b9aca6d..0000000 --- a/templates/pages/create_match.html +++ /dev/null @@ -1,848 +0,0 @@ -{% extends "layouts/base.html" %} -{% block title %}Schedule Match - {{ tryout.title }} - TryoutPro{% endblock %} -{% block page_title %}Schedule Match{% endblock %} -{% block breadcrumb %}Home / Tryouts / {{ tryout.title }} / Schedule Match{% endblock %} - -{% block content %} -
-
-

Schedule Match for {{ tryout.title }}

-
-
-
- - -
- - -
- -
- - -
- -
-
- - -
-
- - -
-
- - - {% if current_user.can_manage_teams() or current_user.can_schedule_matches() %} -
-

Select Match Time

-

Click time slots consecutively to set match duration. Players available in all selected time blocks will be preselected.

- - - -
-

Loading availability...

-
- -
-
- - -
-
- - -
-
- {% else %} - -
-
- - -
-
- - -
-
- {% endif %} - -
- - -
- - -
-
-

Select Teams

- -
-
- - -
-
- - -
-
-
- - - - - - - -
- - - Cancel - -
-
-
-
-{% endblock %} - -{% block scripts %} - - -{% endblock %} \ No newline at end of file diff --git a/templates/pages/create_tryout.html b/templates/pages/create_tryout.html deleted file mode 100644 index 7a89be5..0000000 --- a/templates/pages/create_tryout.html +++ /dev/null @@ -1,64 +0,0 @@ -{% extends "layouts/base.html" %} -{% block title %}Create Tryout - TryoutPro{% endblock %} -{% block page_title %}Create Tryout{% endblock %} -{% block breadcrumb %}Home / Tryouts / Create{% endblock %} - -{% block content %} -
-
-
- -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
-
- - -
-
- Cancel - -
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/templates/pages/dashboard.html b/templates/pages/dashboard.html index e9bfdaf..3c4e91b 100644 --- a/templates/pages/dashboard.html +++ b/templates/pages/dashboard.html @@ -108,6 +108,32 @@ + {% if stats.upcoming_matches %} +
+
+

Upcoming Matches

+
+
+ + + + {% for match in stats.upcoming_matches %} + + + + + + + {% endfor %} + +
MatchTryoutDate & TimeStatus
{{ match.title }}{{ match.tryout.title }} + {{ match.date.strftime('%m/%d/%Y') }} + {% if match.start_time %} at {{ match.start_time.strftime('%I:%M %p') }}{% endif %} + {{ match.status }}
+
+
+ {% endif %} + {% elif user.role == 'manager' %}
@@ -166,6 +192,32 @@
+ {% if stats.upcoming_matches %} +
+
+

Upcoming Matches

+
+
+ + + + {% for match in stats.upcoming_matches %} + + + + + + + {% endfor %} + +
MatchTryoutDate & TimeStatus
{{ match.title }}{{ match.tryout.title }} + {{ match.date.strftime('%m/%d/%Y') }} + {% if match.start_time %} at {{ match.start_time.strftime('%I:%M %p') }}{% endif %} + {{ match.status }}
+
+
+ {% endif %} + {% elif user.role == 'coach' %}
diff --git a/templates/pages/edit_tryout.html b/templates/pages/edit_tryout.html deleted file mode 100644 index 4833406..0000000 --- a/templates/pages/edit_tryout.html +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "layouts/base.html" %} -{% block title %}Edit Tryout - TryoutPro{% endblock %} -{% block page_title %}Edit Tryout{% endblock %} -{% block breadcrumb %}Home / Tryouts / {{ tryout.title }} / Edit{% endblock %} - -{% block content %} -
-
-
- -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
-
- - -
-
- Cancel - -
-
-
-
-{% endblock %} \ No newline at end of file diff --git a/templates/pages/edit_match.html b/templates/pages/match_form.html similarity index 83% rename from templates/pages/edit_match.html rename to templates/pages/match_form.html index 34ddcf0..f2f9533 100644 --- a/templates/pages/edit_match.html +++ b/templates/pages/match_form.html @@ -1,28 +1,54 @@ {% extends "layouts/base.html" %} -{% block title %}Edit Match - TryoutPro{% endblock %} -{% block page_title %}Edit Match{% endblock %} -{% block breadcrumb %}Home / Tryouts / {{ tryout.title }} / Edit Match{% endblock %} +{% block title %}{% if match %}Edit Match{% else %}Schedule Match{% endif %} - {{ tryout.title }} - TryoutPro{% endblock %} +{% block page_title %}{% if match %}Edit Match{% else %}Schedule Match{% endif %}{% endblock %} +{% block breadcrumb %} + + Home / Tryouts + / {{ tryout.title }} + {% if match %} + / Edit Match + {% else %} + / Schedule Match + {% endif %} + +{% endblock %} {% block content %}
-

Edit Match

-

Match Type: {{ match.match_type.replace('_', ' ').title() }}

+

{% if match %}Edit Match{% else %}Schedule Match for {{ tryout.title }}{% endif %}

+ {% if match %} +

Match Type: {{ match.match_type.replace('_', ' ') | title }}

+ {% endif %}
-
+ + {% if not match %} +
+ + +
+ {% else %} + + {% endif %} +
- +
- +
+ {% if match %}
+ {% endif %} +
+ + +
@@ -52,11 +83,11 @@
- +
- +
{% else %} @@ -64,29 +95,24 @@
- +
- +
{% endif %} -
- - -
-
- +
-
+

-

Teams

+

Select Teams

@@ -94,7 +120,7 @@
@@ -103,15 +129,14 @@
- + {% if match and match.team1 %}
- {% if match.team1 %}
{{ match.team1.name }}
    @@ -122,8 +147,10 @@ {% endfor %}
- {% endif %} - {% if match.team2 %} +
+ {% endif %} + {% if match and match.team2 %} +
{{ match.team2.name }}
    @@ -134,12 +161,12 @@ {% endfor %}
- {% endif %}
+ {% endif %}
-
+

Select Players

@@ -181,7 +208,7 @@
-
+

Select Players

@@ -192,7 +219,7 @@
{% for player in all_players %} @@ -202,7 +229,7 @@
Cancel @@ -373,9 +400,11 @@ var allRegisteredPlayers = [ {%- endfor %} ]; +{% if match %} // Current team assignments from server var initialTeam1Ids = {{ team1_player_ids|tojson }}; var initialTeam2Ids = {{ team2_player_ids|tojson }}; +{% endif %} // Time slots from 12pm (12:00) to 12am (24:00) var TIME_SLOTS = []; @@ -427,11 +456,14 @@ document.addEventListener('DOMContentLoaded', function() { selectedDate = this.value; if (allDisponibilitiesInitialized()) { renderMergedDisponibilityGrid(); + {% if match %} updatePlayerPool(); + {% endif %} } }); selectedDate = document.getElementById('date').value; + {% if match %} selectedStartTime = document.getElementById('start_time').value; selectedEndTime = document.getElementById('end_time').value; @@ -459,6 +491,7 @@ document.addEventListener('DOMContentLoaded', function() { // Initialize team assignments for player_vs_player matches // Populate Team 1 + {% if match %} initialTeam1Ids.forEach(function(pid) { var teamDiv = document.getElementById('team1-selection'); var playerName = playerDataById.player_data[pid]; @@ -486,6 +519,13 @@ document.addEventListener('DOMContentLoaded', function() { updateHiddenInputs(); updateRandomizePreview(); + {% endif %} + + {% if not match %} + toggleMatchType(); + // Show all players initially + updatePlayerPool(); + {% endif %} }); function allDisponibilitiesInitialized() { @@ -499,7 +539,9 @@ function fetchDisponibilities() { .then(function(data) { allDisponibilities = data; renderMergedDisponibilityGrid(); + {% if match %} updatePlayerPool(); + {% endif %} }) .catch(function(error) { console.error('Error fetching disponibilities:', error); @@ -666,7 +708,16 @@ function toggleTimeSlot(dayOfWeek, timeStr, element) { }); if (selectedSlots.length > 0) { + {% if match %} fetchAvailablePlayersForSlots(); + {% else %} + fetchAvailablePlayersForAllSlots(); + {% endif %} + } else { + availablePlayersForSlots = []; + {% if match %} + updatePlayerPool(); + {% endif %} } } @@ -692,6 +743,35 @@ function formatTimeDisplay(timeStr) { return displayHour + ':' + m + ' ' + ampm; } +function fetchAvailablePlayersForAllSlots() { + if (!selectedDate || selectedSlots.length === 0) { + availablePlayersForSlots = []; + updatePlayerPool(); + return; + } + + var dateParts = selectedDate.split('-'); + var dateObj = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); + var jsDay = dateObj.getDay(); + var dayOfWeek = jsDay === 0 ? 6 : jsDay - 1; + + // Find players available in ALL selected slots + availablePlayersForSlots = []; + for (var playerId in allDisponibilities) { + if (!allRegisteredPlayers.includes(parseInt(playerId))) continue; + var playerSlots = getSlotsForPlayer(parseInt(playerId), dayOfWeek); + var isAvailableInAll = selectedSlots.every(function(slot) { + return playerSlots.includes(slot); + }); + if (isAvailableInAll) { + availablePlayersForSlots.push(parseInt(playerId)); + } + } + + // Preselect available players in Team 1 + preselectAvailablePlayers(); +} + function fetchAvailablePlayersForSlots() { if (!selectedDate || selectedSlots.length === 0) return; @@ -713,20 +793,15 @@ function fetchAvailablePlayersForSlots() { } } + availablePlayersForSlots = availableIds; // Update player pool for PvP section updatePlayerPool(); updateRandomizePreview(); } -function clearTimeSelection() { - selectedSlots = []; - document.getElementById('start_time').value = ''; - document.getElementById('end_time').value = ''; - document.getElementById('merged-disponibility-selected').classList.add('hidden'); - document.querySelectorAll('.merged-disponibility-time-block').forEach(function(el) { - el.classList.remove('selected'); - }); - availablePlayersForSlots = []; +function preselectAvailablePlayers() { + // Just update the player pool - don't auto-assign to Team 1 + // Players will be shown in the pool and can be manually assigned to either team updatePlayerPool(); } @@ -827,10 +902,47 @@ function updateHiddenInputs() { document.getElementById('team2-player-ids-input').value = team2Ids.join(','); } +function clearTimeSelection() { + selectedSlots = []; + document.getElementById('start_time').value = ''; + document.getElementById('end_time').value = ''; + document.getElementById('merged-disponibility-selected').classList.add('hidden'); + document.querySelectorAll('.merged-disponibility-time-block').forEach(function(el) { + el.classList.remove('selected'); + }); + availablePlayersForSlots = []; + // Clear both team selections + document.querySelectorAll('#team1-selection [data-player-id], #team2-selection [data-player-id]').forEach(function(el) { + el.remove(); + }); + updateHiddenInputs(); + updatePlayerPool(); +} + +function toggleMatchType() { + var matchType = document.getElementById('match_type').value; + var teamSection = document.getElementById('team-vs-team-section'); + var playerVsPlayerSection = document.getElementById('player-vs-player-section'); + var scrimSection = document.getElementById('player-scrim-section'); + + teamSection.classList.add('hidden'); + playerVsPlayerSection.classList.add('hidden'); + scrimSection.classList.add('hidden'); + + if (matchType === 'team_vs_team') { + teamSection.classList.remove('hidden'); + } else if (matchType === 'player_vs_player') { + playerVsPlayerSection.classList.remove('hidden'); + updatePlayerPool(); + } else if (matchType === 'player_scrim') { + scrimSection.classList.remove('hidden'); + } +} + function updateRandomizePreview() { - var assignedCount = document.querySelectorAll('#team1-selection [data-player-id], #team2-selection [data-player-id]').length; + var checkedCount = document.querySelectorAll('#team1-selection [data-player-id], #team2-selection [data-player-id]').length; var team1Size = parseInt(document.getElementById('team1-size').value) || 1; - var team2Size = assignedCount - team1Size; + var team2Size = checkedCount - team1Size; if (team2Size < 0) team2Size = 0; diff --git a/templates/pages/tryout_form.html b/templates/pages/tryout_form.html new file mode 100644 index 0000000..391e05e --- /dev/null +++ b/templates/pages/tryout_form.html @@ -0,0 +1,104 @@ +{% extends "layouts/base.html" %} +{% block title %}{% if tryout %}Edit Tryout{% else %}Create Tryout{% endif %} - TryoutPro{% endblock %} +{% block page_title %}{% if tryout %}Edit Tryout{% else %}Create Tryout{% endif %}{% endblock %} +{% block breadcrumb %} + + Home / Tryouts + {% if tryout %} + / {{ tryout.title }} + / Edit + {% else %} + / Create + {% endif %} + +{% endblock %} + +{% block content %} +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+ + +
+
+ + Cancel + + +
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/pages/view_tryout.html b/templates/pages/view_tryout.html index 282d175..0ee7b75 100644 --- a/templates/pages/view_tryout.html +++ b/templates/pages/view_tryout.html @@ -55,6 +55,14 @@ Target Team {{ tryout.target_org_team.name if tryout.target_org_team else 'Not specified' }}
+
+ Manager + {{ tryout.manager.full_name if tryout.manager else 'Not assigned' }} +
+
+ Coach + {{ tryout.coach.full_name if tryout.coach else 'Not assigned' }} +
Registered Players {{ registered_players | length }}