<%= content_for :title, "Analytics" %> <%= turbo_frame_tag 'main' do %> <%= turbo_stream.append 'flash', partial: 'layouts/flash' %>

<%= yield(:title) %>

<% { "all" => "All time", "30d" => "30 days", "7d" => "7 days", "24h" => "24 hours" }.each do |key, label| %> <%= link_to label, url_for(period: key), class: class_names("analytics-period", current: period == key), data: { turbo_frame: "main", turbo_action: "advance" } %> <% end %>
<% if DemoActivity::ENABLED %>

Demo data is on. DemoActivity keeps inventing players with no gameplay to feed the leaderboard banner, so the counts below are inflated and the funnel shows a large drop before "Facts". Set DemoActivity::ENABLED = false and wipe the players table before go-live.

<% end %>
<%= render "card", label: "Players started", value: number_with_delimiter(@analytics.total_players) %> <%= render "card", label: "Finished", value: number_with_delimiter(@analytics.completed_players), sub: "#{@analytics.completion_rate}% of starters" %> <%= render "card", label: "Median play time", value: format_duration(@analytics.median_duration) %> <%= render "card", label: "Average score", value: (@analytics.average_score || "—") %>

Did you like this game?

<% ratings = @analytics.ratings %> <% if ratings[:total].zero? %>

No votes yet.

<% else %>
<%= render "card", label: "Thumbs up", value: number_with_delimiter(ratings[:up]), sub: "#{ratings[:up_share]}%", modifier: "positive" %> <%= render "card", label: "Thumbs down", value: number_with_delimiter(ratings[:down]), sub: "#{ratings[:down_share]}%", modifier: "negative" %> <%= render "card", label: "Votes", value: number_with_delimiter(ratings[:total]), sub: "#{ratings[:response_rate]}% of players who reached the results" %>
<% end %>

Funnel

How far players got. The last-save early exit is a branch off the stages, so it is reported separately below rather than as a funnel step.

<% @analytics.funnel.each do |row| %>
<%= row[:label] %>
<%= number_with_delimiter(row[:reached]) %> <%= row[:share] %>%
<% if row[:lost] > 0 %> -<%= number_with_delimiter(row[:lost]) %> (<%= row[:lost_share] %>%) <% end %>
<% end %>

Where unfinished players stopped

<% if @analytics.drop_off_points.empty? %>

Nobody has abandoned a game yet.

<% else %>
<% max = @analytics.drop_off_points.first[:count] %> <% @analytics.drop_off_points.each do |row| %>
<%= row[:label] %>
<%= number_with_delimiter(row[:count]) %>
<% end %>
<% end %>

Answers by stage

<% @analytics.stages.each do |stage| %>

<%= stage[:index] %> <%= stage[:node].title %> <%= number_with_delimiter(stage[:total]) %> answers

<% stage[:answers].each do |answer| %>
<%= answer[:label] %> <%= tag.em(answer[:node].template.humanize) %>
<%= number_with_delimiter(answer[:count]) %> <%= answer[:share] %>%
<% answer[:outcomes].each do |outcome| %>
↳ <%= outcome[:label] %> <%= tag.em(outcome[:node].template.humanize) %>
<%= number_with_delimiter(outcome[:count]) %> <%= outcome[:share] %>% of chances
<% end %> <% end %>
<% end %>
<% if @analytics.last_save[:node] %>

Last save early exit — <%= number_with_delimiter(@analytics.last_save[:total]) %> players

<% if @analytics.last_save[:total].zero? %>

No player has taken the early exit yet.

<% else %>
<% @analytics.last_save[:answers].each do |answer| %>
<%= answer[:label] %>
<%= number_with_delimiter(answer[:count]) %> <%= answer[:share] %>%
<% end %>
<% end %>
<% end %>

Endings finished players, excluding early exits

<% @analytics.result_bands.each do |band| %>
<%= t("game.results.#{band[:band]}.headline", default: band[:band].to_s.humanize).html_safe %>
<%= number_with_delimiter(band[:count]) %> <%= band[:share] %>%
<% end %>
<%= render "breakdown", title: "How they got here", note: "Where the scan came from. Each printed QR code carries its own " \ "utm_content tag, so the rows below are the physical placements. " \ "The board game QR points at dice.ikeafoundation.org and is counted there, not here.", rows: @analytics.by_source, labeller: ->(key) { source_breakdown_label(key) } %>
<%= render "breakdown", title: "Devices", rows: @analytics.by_device, labeller: ->(key) { device_breakdown_label(key) } %> <%= render "breakdown", title: "Languages", rows: @analytics.by_locale, labeller: ->(key) { language_breakdown_label(key) } %> <%= render "breakdown", title: "Countries", rows: @analytics.by_country, labeller: ->(key) { country_breakdown_label(key) } %>
<% end %>