Skip to content

Commit

Permalink
Reformat User Show page + add tooltips
Browse files Browse the repository at this point in the history
Expand User stats to include Game Type breakdowns.

Split User stats into 2 columns. This utilizes some of the horizontal
space available to us on non-mobile screens.

Recreate the tooltips from the Game Results view here, as viewers are
likely to have the same questions on these terms.
  • Loading branch information
Paul DobbinSchmaltz committed Oct 25, 2024
1 parent f918e11 commit 266a1aa
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 63 deletions.
10 changes: 5 additions & 5 deletions app/models/board/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
# Board::Settings stores the {#type}, {#width}, {#height}, and number of
# {#mines} (to be) in the {Grid} of a {Board}'s associated {Cell}s.
class Board::Settings
# rubocop:disable Layout/HashAlignment
# rubocop:disable Layout/HashAlignment, Layout/LineLength
PRESETS = {
"Beginner" => { width: 9, height: 9, mines: 10 }, # 12.3% mine density
"Intermediate" => { width: 16, height: 16, mines: 40 }, # 15.6% mine density
"Expert" => { width: 30, height: 16, mines: 99 }, # 20.6% mine density
BEGINNER = "Beginner" => { width: 9, height: 9, mines: 10 }, # 12.3% mine density
INTERMEDIATE = "Intermediate" => { width: 16, height: 16, mines: 40 }, # 15.6% mine density
EXPERT = "Expert" => { width: 30, height: 16, mines: 99 }, # 20.6% mine density
}.freeze
# rubocop:enable Layout/HashAlignment
# rubocop:enable Layout/HashAlignment, Layout/LineLength

ALL_TYPES = [
*PRESETS.keys,
Expand Down
5 changes: 5 additions & 0 deletions app/models/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class Game < ApplicationRecord
])

scope :for_type, ->(type) { where(type:) }
scope :for_beginner_type, -> { where(type: Board::Settings::BEGINNER) }
scope :for_intermediate_type, -> {
where(type: Board::Settings::INTERMEDIATE)
}
scope :for_expert_type, -> { where(type: Board::Settings::EXPERT) }
scope :for_game_on_statuses, -> {
for_status([status_standing_by, status_sweep_in_progress])
}
Expand Down
125 changes: 89 additions & 36 deletions app/views/users/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,87 +24,140 @@
<div class="space-y-6">
<h3>Stats</h3>

<div class="flex flex-col md:flex-row gap-x-24 gap-y-8 items-start">
<table>
<tbody class="*:*:px-3 *:*:py-1">
<div
class="
flex flex-col md:flex-row
gap-x-24 gap-y-8
items-start
"
>
<table
class="
border-separate
border-spacing-x-3 border-spacing-y-1
-mx-3 -my-1
text-left
"
>
<tbody>
<tr>
<th class="text-left">Engagements</th>
<th>Engagements</th>
<td><%= @view.games_count %></td>
</tr>
<tr>
<th class="text-left">Victories</th>
<th>Victories</th>
<td><%= @view.winning_games_count %></td>
</tr>
<tr>
<th class="text-left">Defeats</th>
<th>Defeats</th>
<td><%= @view.losing_games_count %></td>
</tr>

<tr><td colspan="100%" class="select-none">&nbsp;</td></tr>

<tr>
<th class="text-left">
Best
<th>Cells Revealed</th>
<td><%= @view.reveals_count %></td>
</tr>
<tr>
<th>
<dfn
data-tooltip="up-left"
aria-label="<%= t("game.stats.score") %>"
aria-label="<%= t("game.stats.chords") %>"
class="after:w-80"
>Score</dfn>
>Chords</dfn>
</th>
<td><%= @view.best_score %></td>
<td><%= @view.chords_count %></td>
</tr>
<tr>
<th>Flags Placed</th>
<td><%= @view.flags_count %></td>
</tr>
<tr>
<th class="text-left">
<th>Flags Removed</th>
<td><%= @view.unflags_count %></td>
</tr>
<tr>
<th>Mines Detonated</th>
<td><%= @view.tripped_mines_count %></td>
</tr>
</tbody>
</table>

<table
class="
border-separate
border-spacing-x-3 border-spacing-y-1
-mx-3 -my-1
text-left
"
>
<tbody>
<tr>
<th>
Best
<dfn
data-tooltip="up-left"
aria-label="<%= t("game.stats.bbbvps") %>"
aria-label="<%= t("game.stats.score") %>"
class="after:w-80"
>3BV/s</dfn>
>Score</dfn>
</th>
<td><%= @view.best_bbbvps %></td>
</tr>
<tr>
<th class="text-left">
<th class="pl-6">Beginner</th>
<td><%= @view.best_beginner_score %></td>
</tr>
<tr>
<th class="pl-6">Intermediate</th>
<td><%= @view.best_intermediate_score %></td>
</tr>
<tr>
<th class="pl-6">Expert</th>
<td><%= @view.best_expert_score %></td>
</tr>
<tr>
<th>
Best
<dfn
data-tooltip="up-left"
aria-label="<%= t("game.stats.efficiency") %>"
aria-label="<%= t("game.stats.bbbvps") %>"
class="after:w-80"
>Efficiency</dfn>
>3BV/s</dfn>
</th>
<td><%= @view.best_efficiency %></td>
</tr>
</tbody>
</table>

<table>
<tbody class="*:*:px-3 *:*:py-1">
<tr>
<th class="text-left">Cells Revealed</th>
<td><%= @view.reveals_count %></td>
<th class="pl-6">Beginner</th>
<td><%= @view.best_beginner_bbbvps %></td>
</tr>
<tr>
<th class="text-left">
<th class="pl-6">Intermediate</th>
<td><%= @view.best_intermediate_bbbvps %></td>
</tr>
<tr>
<th class="pl-6">Expert</th>
<td><%= @view.best_expert_bbbvps %></td>
</tr>
<tr>
<th>
Best
<dfn
data-tooltip="up-left"
aria-label="<%= t("game.stats.chords") %>"
aria-label="<%= t("game.stats.efficiency") %>"
class="after:w-80"
>Chords</dfn>
>Efficiency</dfn>
</th>
<td><%= @view.chords_count %></td>
</tr>
<tr>
<th class="text-left">Flags Placed</th>
<td><%= @view.flags_count %></td>
<th class="pl-6">Beginner</th>
<td><%= @view.best_beginner_efficiency %></td>
</tr>
<tr>
<th class="text-left">Flags Removed</th>
<td><%= @view.unflags_count %></td>
<th class="pl-6">Intermediate</th>
<td><%= @view.best_intermediate_efficiency %></td>
</tr>
<tr>
<th class="text-left">Mines Detonated</th>
<td><%= @view.tripped_mines_count %></td>
<th class="pl-6">Expert</th>
<td><%= @view.best_expert_efficiency %></td>
</tr>
</tbody>
</table>
Expand Down
75 changes: 53 additions & 22 deletions app/views/users/show.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,45 +36,45 @@ def flags_count = delimit(_flags_count)
def unflags_count = delimit(_unflags_count)
def tripped_mines_count = delimit(_tripped_mines_count)

def best_score
score = _best_score
score ? score.round(DEFAULT_PRECISION) : NO_VALUE_INDICATOR
end

def best_bbbvps
bbbvps = _best_bbbvps
bbbvps ? bbbvps.round(DEFAULT_PRECISION) : NO_VALUE_INDICATOR
end

def best_efficiency
efficiency = _best_efficiency
efficiency ? percentage(efficiency * 100.0) : NO_VALUE_INDICATOR
end
def best_overall_score = best_score(_best_overall_score)
def best_beginner_score = best_score(_best_beginner_score)
def best_intermediate_score = best_score(_best_intermediate_score)
def best_expert_score = best_score(_best_expert_score)

def best_overall_bbbvps = best_bbbvps(_best_overall_bbbvps)
def best_beginner_bbbvps = best_bbbvps(_best_beginner_bbbvps)
def best_intermediate_bbbvps = best_bbbvps(_best_intermediate_bbbvps)
def best_expert_bbbvps = best_bbbvps(_best_expert_bbbvps)

# rubocop:disable Layout/LineLength
def best_overall_efficiency = best_efficiency(_best_overall_efficiency)
def best_beginner_efficiency = best_efficiency(_best_beginner_efficiency)
def best_intermediate_efficiency = best_efficiency(_best_intermediate_efficiency)
def best_expert_efficiency = best_efficiency(_best_expert_efficiency)
# rubocop:enable Layout/LineLength

private

attr_reader :user

def games = user.games

def _completed_games_count
@_completed_games_count ||= games.for_game_over_statuses.size
@_completed_games_count ||= games_arel.for_game_over_statuses.size
end

def winning_games_percentage = percentage(winning_games_percent)
def winning_games_percent = winning_games_ratio * 100.0
def winning_games_ratio = _winning_games_count / _completed_games_count.to_f

def _winning_games_count
@_winning_games_count ||= games.for_status_alliance_wins.size
@_winning_games_count ||= games_arel.for_status_alliance_wins.size
end

def losing_games_percentage = percentage(losing_games_percent)
def losing_games_percent = losing_games_ratio * 100.0
def losing_games_ratio = _losing_games_count / _completed_games_count.to_f

def _losing_games_count
@_losing_games_count ||= games.for_status_mines_win.size
@_losing_games_count ||= games_arel.for_status_mines_win.size
end

def _reveals_count = cell_reveal_transactions.size
Expand All @@ -91,9 +91,40 @@ def cell_unflag_transactions = user.cell_unflag_transactions

def _tripped_mines_count = user.revealed_cells.is_mine.size

def _best_score = user.games.by_score_asc.pick(:score)
def _best_bbbvps = user.games.by_bbbvps_desc.pick(:bbbvps)
def _best_efficiency = user.games.by_efficiency_desc.pick(:efficiency)
def best_score(value)
valuify(value) { |score| score.round(DEFAULT_PRECISION) }
end

def _best_beginner_score = _best_score(games_arel.for_beginner_type)
def _best_intermediate_score = _best_score(games_arel.for_intermediate_type)
def _best_expert_score = _best_score(games_arel.for_expert_type)
def _best_score(arel) = arel.by_score_asc.pick(:score)

def best_bbbvps(value)
valuify(value) { |bbbvps| bbbvps.round(DEFAULT_PRECISION) }
end

def _best_beginner_bbbvps = _best_bbbvps(games_arel.for_beginner_type)
def _best_intermediate_bbbvps = _best_bbbvps(games_arel.for_intermediate_type)
def _best_expert_bbbvps = _best_bbbvps(games_arel.for_expert_type)
def _best_bbbvps(arel) = arel.by_bbbvps_desc.pick(:bbbvps)

def best_efficiency(value)
valuify(value) { |efficiency| percentage(efficiency * 100.0) }
end

# rubocop:disable Layout/LineLength
def _best_beginner_efficiency = _best_efficiency(games_arel.for_beginner_type)
def _best_intermediate_efficiency = _best_efficiency(games_arel.for_intermediate_type)
def _best_expert_efficiency = _best_efficiency(games_arel.for_expert_type)
def _best_efficiency(arel) = arel.by_efficiency_desc.pick(:efficiency)
# rubocop:enable Layout/LineLength

def games_arel = user.games

def valuify(value)
value ? yield(value) : NO_VALUE_INDICATOR
end

def percentage(value, precision: DEFAULT_PRECISION)
helpers.number_to_percentage(value, precision:)
Expand Down

0 comments on commit 266a1aa

Please sign in to comment.