Add Elo rating system with match entry and CSV upload
- Implement EloCalculator service for 2v2 Euchre matches - Create background job processing with GoodJob - Add single match entry form - Add CSV upload for batch match entry - Create player rankings view - Add database schema for matches and elo snapshots
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<h1>Match Administration</h1>
|
||||
|
||||
<p><a href="/admin/matches/new">Enter New Match</a> | <a href="/admin/matches/upload">Upload CSV</a></p>
|
||||
|
||||
<% if matches.any? %>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Date</th>
|
||||
<th>Team 1</th>
|
||||
<th>Score</th>
|
||||
<th>Team 2</th>
|
||||
<th>Score</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% matches.each do |match| %>
|
||||
<tr>
|
||||
<td><%= match.id %></td>
|
||||
<td><%= match.played_at&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td><%= match.team_1_p1_id %>/<%= match.team_1_p2_id %></td>
|
||||
<td><%= match.team_1_score %></td>
|
||||
<td><%= match.team_2_p1_id %>/<%= match.team_2_p2_id %></td>
|
||||
<td><%= match.team_2_score %></td>
|
||||
<td><%= match.status %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<p>No matches entered yet.</p>
|
||||
<% end %>
|
||||
|
||||
<p><a href="/admin/players">Manage Players</a></p>
|
||||
@@ -0,0 +1,66 @@
|
||||
<h1>Enter New Match</h1>
|
||||
|
||||
<form action="/admin/matches" method="post">
|
||||
<input type="hidden" name="_csrf_token" value="<%= csrf_token %>">
|
||||
|
||||
<div>
|
||||
<label for="played_at">Date/Time:</label>
|
||||
<input type="datetime-local" id="played_at" name="played_at" required value="<%= Time.now.strftime('%Y-%m-%dT%H:%M') %>">
|
||||
</div>
|
||||
|
||||
<fieldset>
|
||||
<legend>Team 1</legend>
|
||||
<div>
|
||||
<label for="team_1_p1_id">Player 1:</label>
|
||||
<select id="team_1_p1_id" name="team_1_p1_id" required>
|
||||
<option value="">Select player...</option>
|
||||
<% players.each do |player| %>
|
||||
<option value="<%= player.id %>"><%= player.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="team_1_p2_id">Player 2:</label>
|
||||
<select id="team_1_p2_id" name="team_1_p2_id" required>
|
||||
<option value="">Select player...</option>
|
||||
<% players.each do |player| %>
|
||||
<option value="<%= player.id %>"><%= player.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="team_1_score">Score:</label>
|
||||
<input type="number" id="team_1_score" name="team_1_score" min="0" max="10" required value="10">
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Team 2</legend>
|
||||
<div>
|
||||
<label for="team_2_p1_id">Player 1:</label>
|
||||
<select id="team_2_p1_id" name="team_2_p1_id" required>
|
||||
<option value="">Select player...</option>
|
||||
<% players.each do |player| %>
|
||||
<option value="<%= player.id %>"><%= player.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="team_2_p2_id">Player 2:</label>
|
||||
<select id="team_2_p2_id" name="team_2_p2_id" required>
|
||||
<option value="">Select player...</option>
|
||||
<% players.each do |player| %>
|
||||
<option value="<%= player.id %>"><%= player.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="team_2_score">Score:</label>
|
||||
<input type="number" id="team_2_score" name="team_2_score" min="0" max="10" required value="7">
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<button type="submit">Save Match</button>
|
||||
</form>
|
||||
|
||||
<p><a href="/admin/matches">Back to Matches</a></p>
|
||||
@@ -0,0 +1,26 @@
|
||||
<h1>Upload Matches (CSV)</h1>
|
||||
|
||||
<p>Upload a CSV file with the following columns:</p>
|
||||
<pre>
|
||||
played_at, team_1_p1_name, team_1_p2_name, team_1_score, team_2_p1_name, team_2_p2_name, team_2_score
|
||||
</pre>
|
||||
|
||||
<form action="/admin/matches/process_upload" method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_csrf_token" value="<%= csrf_token %>">
|
||||
|
||||
<div>
|
||||
<label for="csv_file">CSV File:</label>
|
||||
<input type="file" id="csv_file" name="csv_file" accept=".csv" required>
|
||||
</div>
|
||||
|
||||
<button type="submit">Upload</button>
|
||||
</form>
|
||||
|
||||
<p><a href="/admin/matches">Back to Matches</a></p>
|
||||
|
||||
<h2>Example CSV:</h2>
|
||||
<pre>
|
||||
played_at,team_1_p1_name,team_1_p2_name,team_1_score,team_2_p1_name,team_2_p2_name,team_2_score
|
||||
2026-03-26 10:00,Alice,Bob,10,Charlie,David,7
|
||||
2026-03-26 10:30,Alice,Bob,10,Charlie,David,7
|
||||
</pre>
|
||||
@@ -0,0 +1,28 @@
|
||||
<h1>Player Rankings</h1>
|
||||
|
||||
<% if players.any? %>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Player</th>
|
||||
<th>Elo Rating</th>
|
||||
<th>Original Rating</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% players.each_with_index do |player, index| %>
|
||||
<tr>
|
||||
<td><%= index + 1 %></td>
|
||||
<td><%= player.name %></td>
|
||||
<td><strong><%= player.current_elo %></strong></td>
|
||||
<td><%= player.rating %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<p>No players found.</p>
|
||||
<% end %>
|
||||
|
||||
<p><a href="/admin/players">Admin</a></p>
|
||||
Reference in New Issue
Block a user