feat(players): add player profile and schedule views

Implement player-facing views for profile analytics and tournament scheduling.

Changes:
- Add player profile page with partnership statistics
- Add player schedule page with upcoming matches
- Update rankings page to link to player profiles
- Add partnership tracking display in profile
- Include recent games timeline in profile

Note: Schedule view shows upcoming matches and tournament participation
This commit is contained in:
2026-03-27 12:25:14 -07:00
parent e7ddd0f72f
commit 841caa50fa
4 changed files with 387 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
<h1>Player Profile: <%= player.name %></h1>
<div class="profile-header">
<div class="player-stats">
<div class="stat">
<span class="label">ELO Rating</span>
<span class="value"><%= player.current_elo %></span>
</div>
<div class="stat">
<span class="label">Total Games</span>
<span class="value"><%= recent_games.count %></span>
</div>
<div class="stat">
<span class="label">Win Rate</span>
<span class="value"><%= (recent_games.count > 0 ? (recent_games.count { |g| g[:won] }.to_f / recent_games.count * 100).round(1) : 0) %>%</span>
</div>
</div>
</div>
<hr>
<h2>Partnership Performance</h2>
<% if partnerships.any? %>
<div class="partnerships-table">
<table>
<thead>
<tr>
<th>Partner</th>
<th>Games</th>
<th>Win Rate</th>
<th>ELO Change</th>
<th>Avg/Match</th>
<th>Last Played</th>
</tr>
</thead>
<tbody>
<% partnerships.each do |p| %>
<tr>
<td><a href="/players/<%= p[:partner][:id] %>"><%= p[:partner][:name] %></a></td>
<td><%= p[:games_played] %></td>
<td>
<%= (p[:win_rate] * 100).round(1) %>%
<div class="confidence-<%= p[:games_played] >= 30 ? 'high' : p[:games_played] >= 15 ? 'medium' : 'low' %>">
<% if p[:games_played] < 15 %>
<small>(low confidence)</small>
<% end %>
</div>
</td>
<td><%= p[:total_elo_change] > 0 ? "+" : "" %><%= p[:total_elo_change] %></td>
<td><%= p[:avg_elo_change] > 0 ? "+" : "" %><%= p[:avg_elo_change] %></td>
<td><%= p[:last_played]&.strftime('%Y-%m-%d') || '-' %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<p>No partnership data available yet.</p>
<% end %>
<hr>
<h2>Recent Games</h2>
<% if recent_games.any? %>
<div class="recent-games">
<% recent_games.each do |game| %>
<div class="game <%= game[:won] ? 'won' : 'lost' %>">
<div class="game-date">
<%= game[:date]&.strftime('%Y-%m-%d %H:%M') || 'N/A' %>
</div>
<div class="game-teams">
<div class="team team-1 <%= game[:won] ? 'winner' : '' %>">
<%= game[:team_1].map { |p| p[:name] }.join(' + ') %>
</div>
<div class="game-score">
<%= game[:score] %>
</div>
<div class="team team-2 <%= !game[:won] ? 'winner' : '' %>">
<%= game[:team_2].map { |p| p[:name] }.join(' + ') %>
</div>
</div>
<div class="game-partner">
Partner: <%= game[:player_partner][:name] %>
</div>
</div>
<% end %>
</div>
<% else %>
<p>No games played yet.</p>
<% end %>
<p><a href="/rankings">Back to Rankings</a></p>
+90
View File
@@ -0,0 +1,90 @@
<h1><%= player.name %>'s Schedule</h1>
<div class="schedule-container">
<!-- Upcoming Matches Section -->
<section class="upcoming-matches">
<h2>Upcoming Matches</h2>
<% if upcoming_matches.any? %>
<div class="matches-list">
<% upcoming_matches.each do |match| %>
<div class="match-card">
<div class="match-date">
<%= match[:date]&.strftime('%a, %b %d') || 'TBD' %>
<%= match[:date]&.strftime('%I:%M %p') %>
</div>
<div class="match-details">
<div class="teams">
<div class="team your-team">
<%= match[:player_team].map { |p| p[:name] }.join(' + ') %>
</div>
<div class="vs">vs</div>
<div class="team opponent-team">
<%= match[:opponent_team].map { |p| p[:name] }.join(' + ') %>
</div>
</div>
</div>
<div class="match-actions">
<a href="/admin/matches/<%= match[:id] %>/edit" class="btn btn-small">Record Result</a>
</div>
</div>
<% end %>
</div>
<% else %>
<p class="no-matches">No upcoming matches scheduled.</p>
<% end %>
</section>
<!-- Active Tournaments Section -->
<section class="active-tournaments">
<h2>Active Tournaments</h2>
<% if active_tournaments.any? %>
<div class="tournaments-list">
<% active_tournaments.each do |tournament| %>
<div class="tournament-card">
<div class="tournament-info">
<h3><%= tournament[:name] %></h3>
<p class="tournament-format"><%= tournament[:format].capitalize %> Tournament</p>
</div>
<div class="tournament-status">
<span class="status-badge <%= tournament[:status] %>"><%= tournament[:status].capitalize %></span>
</div>
<div class="tournament-actions">
<a href="/admin/tournaments/<%= tournament[:id] %>" class="btn btn-small">View Details</a>
</div>
</div>
<% end %>
</div>
<% else %>
<p class="no-tournaments">No active tournaments.</p>
<% end %>
</section>
<!-- Tournament Schedule Section -->
<section class="tournament-schedule">
<h2>Tournament Schedule</h2>
<% if tournament_schedule.any? %>
<div class="schedule-by-tournament">
<% tournament_schedule.each do |schedule| %>
<div class="tournament-schedule-item">
<h3><%= schedule[:tournament][:name] %></h3>
<div class="rounds">
<% schedule[:rounds].each do |round| %>
<div class="round">
<span class="round-number">Round <%= round[:round_number] %></span>
<span class="round-status"><%= round[:status] %></span>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<% else %>
<p class="no-schedule">No tournament schedule available.</p>
<% end %>
</section>
</div>
<p><a href="/players/<%= player.id %>/profile">Back to Profile</a></p>