vol1ura/Sat_9am_5km

View on GitHub
app/views/athletes/show.html.erb

Summary

Maintainability
Test Coverage
<%
  athlete_name = @athlete.name || t('common.nobody')
  seconds_in_results = @athlete.stats.dig('results', 'seconds') || []
  seconds_in_results_count = seconds_in_results.size
%>
<% head_info :title, athlete_name %>
<% head_info :description, t('.description', athlete_name:) %>

<div class="row">
  <div class="col-6">
    <h1 class="mt-2"><%= athlete_name %></h1>
  </div>
  <div class="ms-auto col-auto position-relative">
    <%= image_tag user_image_path(@athlete.user), class: 'avatar', title: athlete_name %>
    <a href="#" class="btn btn-outline-primary rounded-circle position-absolute top-0 end-0 me-2" role="button" data-bs-toggle="modal" data-bs-target="#barcodeModal">
      <i class="fa-solid fa-qrcode" title="QR"></i>
    </a>
  </div>
</div>

<div class="accordion accordion-flush" id="accordionPersonalBest" data-controller="athlete">
  <% if @athlete.club %>
    <div class="accordion-item">
      <h2 class="accordion-header" id="flush-club">
        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseClub" aria-expanded="false" aria-controls="flush-collapseClub">
          <span class="badge text-bg-ligth bg-primary me-3"><i class="fa-solid fa-people-group"></i></span>
          <%= @athlete.club.name %>
        </button>
      </h2>
      <div id="flush-collapseClub" class="accordion-collapse collapse" aria-labelledby="flush-club" data-bs-parent="#accordionPersonalBest">
        <div class="accordion-body">
          <%= t  '.show_club_html', link: link_to(@athlete.club.name, @athlete.club) %>
        </div>
      </div>
    </div>
  <% end %>
  <% if @total_results.positive? %>
    <div class="accordion-item">
      <h2 class="accordion-header" id="flush-totalResults">
        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseTotalResults" aria-expanded="false" aria-controls="flush-collapseTotalResults">
          <span class="badge text-bg-ligth bg-primary me-3"><%= @total_results %></span>
          <%= t '.total_results' %>
        </button>
      </h2>
      <div id="flush-collapseTotalResults" class="accordion-collapse collapse" aria-labelledby="flush-totalResults" data-bs-parent="#accordionPersonalBest">
        <div class="accordion-body">
          <div class="d-flex flex-wrap justify-content-around">
            <div id="chart-results" class="col-12 col-md-10 col-xl-8"></div>
          </div>
        </div>
      </div>
    </div>
  <% end %>
  <% if @total_vol.positive? %>
    <div class="accordion-item">
      <h2 class="accordion-header" id="flush-totalVolunteering">
        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseTotalVolunteering" aria-expanded="false" aria-controls="flush-collapseTotalVolunteering">
          <span class="badge text-bg-ligth bg-primary me-3"><%= @total_vol %></span>
          <%= t '.total_volunteering' %>
        </button>
      </h2>
      <div id="flush-collapseTotalVolunteering" class="accordion-collapse collapse" aria-labelledby="flush-totalVolunteering" data-bs-parent="#accordionPersonalBest">
        <div class="accordion-body">
          <ul class="list-group list-group-flush">
            <li class="list-group-item">
              <div class="hstack">
                <div class="acc-li-s"><%= t '.h_index' %></div>
                <div class="mx-3">
                  <abbr title="<%= t '.h_index_explanation' %>" class="initialism">
                    <%= @volunteering.group(:role).reorder(count_all: :desc).count.values.map.with_index.take_while { |count, idx| count > idx }.size %>
                  </abbr>
                </div>
              </div>
            </li>
            <li class="list-group-item">
              <div class="hstack">
                <div class="acc-li-s"><%= t '.volunteering_coefficient' %></div>
                <div class="mx-3">
                  <abbr title="<%= t '.volunteering_coefficient_explanation' %>" class="initialism">
                    <% if @total_results.zero? %>
                      <i class="fa-solid fa-infinity"></i>
                    <% else %>
                      <%= (@total_vol * 10.0 / @total_results).round(1) %>
                    <% end %>
                  </abbr>
                </div>
              </div>
            </li>
          </ul>
        </div>
      </div>
    </div>
  <% end %>
  <% if @total_trophies.positive? %>
    <div class="accordion-item">
      <h2 class="accordion-header" id="flush-totalTrophies">
        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseTotalTrophies" aria-expanded="false" aria-controls="flush-collapseTotalTrophies">
          <span class="badge text-bg-ligth bg-primary me-3"><%= @total_trophies %></span>
          <%= t '.total_trophies' %>
        </button>
      </h2>
      <div id="flush-collapseTotalTrophies" class="accordion-collapse collapse" aria-labelledby="flush-totalTrophies" data-bs-parent="#accordionPersonalBest">
        <div class="accordion-body">
          <div class="d-flex justify-content-start flex-wrap">
            <% if @total_results.positive? && seconds_in_results_count < 60 %>
              <%= render 'minute_bingo', seconds_in_results_count: %>
            <% end %>
            <% @athlete.trophies.includes(badge: { image_attachment: :blob }).order('date ASC NULLS FIRST').each do |trophy| %>
              <div class="p-1">
                <%
                  trophy_link = link_to badge_path(trophy.badge) do
                    image_tag trophy.badge.image.variant(:thumb), class: 'trophy', title: trophy.badge.name
                  end
                %>
                <% if trophy.badge.record_kind? %>
                  <% trophy.info['data'].each do |record_data| %>
                    <%= trophy_link %>
                  <% end %>
                <% else %>
                  <%= trophy_link %>
                <% end %>
              </div>
            <% end %>
          </div>
        </div>
      </div>
    </div>
  <% end %>
  <% if @total_results.positive? %>
    <div class="accordion-item">
      <h2 class="accordion-header" id="flush-totalEvents">
        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseTotalEvents" aria-expanded="false" aria-controls="flush-collapseTotalEvents">
          <span class="badge text-bg-ligth bg-primary me-3"><%= @total_events %></span>
          <%= t '.total_events' %>
        </button>
      </h2>
      <div id="flush-collapseTotalEvents" class="accordion-collapse collapse" aria-labelledby="flush-totalEvents" data-bs-parent="#accordionPersonalBest">
        <div class="accordion-body">
          <div class="d-flex flex-wrap justify-content-around">
            <div id="chart-events-count" class="col-12 col-md-6 col-xl-4"></div>
            <div id="chart-events-whiskers" class="col-12 col-md-6 col-xl-4"></div>
          </div>
        </div>
      </div>
    </div>
    <div class="accordion-item">
      <% pb_result = @pb_by_time.first %>
      <h2 class="accordion-header" id="flush-personalBestAbsolute">
        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapsePersonalBestAbsolute" aria-expanded="false" aria-controls="flush-collapsePersonalBestAbsolute">
          <span class="badge text-bg-ligth bg-primary me-3"><%= pb_result ? human_result_time(pb_result.total_time) : '?' %></span>
          <%= t '.personal_best' %>
        </button>
      </h2>
      <div id="flush-collapsePersonalBestAbsolute" class="accordion-collapse collapse" aria-labelledby="flush-personalBestAbsolute" data-bs-parent="#accordionPersonalBest">
        <div class="accordion-body">
          <table class="table">
            <thead>
              <tr>
                <th><%= t '.table.pb' %></th>
                <th>Δ</th>
                <th><%= t '.table.date' %></th>
                <th><%= t '.table.event' %></th>
              </tr>
            </thead>
            <tbody>
              <% @pb_by_time.includes(activity: :event).to_a.push(nil).each_cons(2) do |pb, pb_prev| %>
                <tr>
                  <td><%= human_result_time pb.total_time %></td>
                  <td>
                    <% if pb_prev %>
                      <% delta = (pb_prev.total_time - pb.total_time).to_i %>
                      <%= format('%d:%02d', delta / 60, delta % 60) %>
                    <% end %>
                  </td>
                  <td><%= link_to l(pb.activity.date), pb.activity %></td>
                  <td><%= link_to pb.activity.event_name, event_path(pb.activity.event.code_name) %></td>
                </tr>
              <% end %>
            </tbody>
          </table>
        </div>
      </div>
    </div>
    <div class="accordion-item">
      <h2 class="accordion-header" id="flush-bestPositionAbsolute">
        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseBestPositionAbsolute" aria-expanded="false" aria-controls="flush-collapseBestPositionAbsolute">
          <span class="badge text-bg-ligth bg-primary me-3"><%= @best_position %></span>
          <%= t '.best_position' %>
        </button>
      </h2>
      <div id="flush-collapseBestPositionAbsolute" class="accordion-collapse collapse" aria-labelledby="flush-bestPositionAbsolute" data-bs-parent="#accordionPersonalBest">
        <div class="accordion-body">
          <ul class="list-group list-group-flush">
            <% @pb_by_position.each do |pb| %>
              <li class="list-group-item">
                <div class="hstack">
                  <div class="acc-li-s">
                    <%= link_to l(pb.activity.date), pb.activity %>
                  </div>
                  <div class="mx-3">
                    <%= human_result_time pb.total_time %>
                  </div>
                  <div>
                    <%= link_to pb.activity.event_name, event_path(pb.activity.event.code_name) %>
                  </div>
                </div>
              </li>
            <% end %>
          </ul>
        </div>
      </div>
    </div>
  <% end %>
</div>

<% if @total_results.zero? %>
  <p><%= t '.no_results' %></p>
<% else %>
  <h2 class="mt-3"><%= t '.results' %></h2>
  <table class="table table-striped">
    <thead>
      <tr>
        <th>#</th>
        <th><%= t '.table.date' %></th>
        <th><%= t '.table.time' %></th>
        <th class="hidden-on-phone"><%= t '.table.pace' %></th>
        <th class="hidden-on-phone"><%= t '.table.place' %></th>
        <th><%= t '.table.event' %></th>
      </tr>
    </thead>
    <tbody class="table-group-divider">
      <%= render partial: 'result', collection: @athlete.results.published.includes(activity: :event).order('activity.date DESC') %>
    </tbody>
  </table>
  <%= render '/expand_button' if @total_results > 15 %>
<% end %>

<h2><%= t '.volunteering' %></h2>
<% if @total_vol.zero? %>
  <p><%= t '.no_volunteering' %></p>
<% else %>
  <div class="accordion accordion-flush" id="accordionRoles">
    <% @volunteering.pluck(:role).uniq.each do |role| %>
      <% volunteering_in_role = @volunteering.includes(activity: :event).where(role:) %>
      <div class="accordion-item">
        <h2 id="flush-heading-<%= role %>" class="accordion-header">
          <button class="accordion-button collapsed position-relative" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapse-<%= role %>" aria-expanded="false" aria-controls="flush-collapse-<%= role %>">
            <span class="badge text-bg-ligth bg-primary me-3"><%= volunteering_in_role.size %></span>
            <%= human_volunteer_role role %>
          </button>
        </h2>
        <div id="flush-collapse-<%= role %>" class="accordion-collapse collapse" aria-labelledby="flush-heading-<%= role %>" data-bs-parent="#accordionRoles">
          <div class="accordion-body">
            <ul class="list-group list-group-flush">
              <% volunteering_in_role.each do |vol| %>
                <li class="list-group-item">
                  <div class="hstack">
                    <div class="acc-li-s">
                      <%= link_to l(vol.activity.date), vol.activity %>
                    </div>
                    <div class="ms-3">
                      <%= link_to vol.activity.event_name, event_path(vol.activity.event.code_name) %>
                    </div>
                  </div>
                </li>
              <% end %>
            </ul>
          </div>
        </div>
      </div>
    <% end %>
  </div>
<% end %>

<!-- Modal barcode -->
<div class="modal fade" id="barcodeModal" tabindex="-1" aria-labelledby="barcodeModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="barcodeModalLabel">A<%= @athlete.code %></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body d-flex justify-content-center">
        <div><%== @barcode %></div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-light" data-bs-dismiss="modal"><%= t '.close' %></button>
      </div>
    </div>
  </div>
</div>
<!-- Modal minute bingo -->
<div class="modal fade" id="minuteBingoModal" tabindex="-1" aria-labelledby="minuteBingoModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h1 class="modal-title fs-5" id="minuteBingoModalLabel"><%= t '.mission_minute_bingo' %></h1>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <table class="mx-auto">
          <% 6.times.each do |row| %>
            <tr>
              <% 10.times.each do |col| %>
                <% x = row * 10 + col %>
                <td class="text-<%= seconds_in_results.include?(x) ? 'primary' : 'light' %>"><%= format '%02d', x %></td>
              <% end %>
            </tr>
          <% end %>
        </table>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-light" data-bs-dismiss="modal"><%= t '.close' %></button>
      </div>
    </div>
  </div>
</div>