Mattias Bodlund 7 months ago
parent
commit
b18d147418
13 changed files with 184 additions and 25 deletions
  1. +1
    -1
      Gemfile.lock
  2. +70
    -21
      app/assets/stylesheets/application.css
  3. +1
    -0
      app/controllers/answers_controller.rb
  4. +9
    -2
      app/controllers/concerns/quiz_helper_methods.rb
  5. +29
    -0
      app/controllers/questions_controller.rb
  6. +2
    -0
      app/models/answer.rb
  7. +28
    -0
      app/models/player.rb
  8. +5
    -1
      app/views/questions/answer.html.erb
  9. +28
    -0
      app/views/questions/result.html.erb
  10. +4
    -0
      config/locales/en.yml
  11. +2
    -0
      config/routes.rb
  12. +3
    -0
      db/migrate/20250429085114_create_players.rb
  13. +2
    -0
      db/schema.rb

+ 1
- 1
Gemfile.lock View File

@ -162,7 +162,7 @@ GEM
i18n (>= 0.6.10, < 2) i18n (>= 0.6.10, < 2)
request_store (~> 1.0) request_store (~> 1.0)
msgpack (1.8.0) msgpack (1.8.0)
net-imap (0.5.7)
net-imap (0.5.8)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)


+ 70
- 21
app/assets/stylesheets/application.css View File

@ -89,7 +89,7 @@
--fs-lg: 1.8rem; --fs-lg: 1.8rem;
--fs-xl: 2.8rem; --fs-xl: 2.8rem;
--fs-2xl: 3.2rem; --fs-2xl: 3.2rem;
--fs-3xl: 5.6rem;
--fs-3xl: 4.0rem;
--fs-4xl: 9.0rem; --fs-4xl: 9.0rem;
--flip-deg: 0deg; --flip-deg: 0deg;
@ -107,13 +107,15 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0; gap: 0;
min-height: 100svh;
justify-content: end;
position: relative;
min-height: 100svh;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
touch-action: manipulation; touch-action: manipulation;
} }
ul[class] { ul[class] {
margin: 0 auto; margin: 0 auto;
padding: 0; padding: 0;
@ -122,11 +124,9 @@ ul[class] {
header { header {
position: fixed;
top: 1.2rem;
left: 1.2rem;
padding: 1.2rem;
flex-grow: 0;
& svg { & svg {
width: 70px; width: 70px;
height: auto; height: auto;
@ -219,7 +219,17 @@ footer {
main { main {
margin: 1.2rem 1.2rem 1.6rem 1.2rem;
margin: 0 1.2rem 1.6rem 1.2rem;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: end;
}
@media (min-width: 474px) {
main {
justify-content: center;
}
} }
.intro-container { .intro-container {
@ -235,6 +245,14 @@ main {
grid-template-columns: 1; grid-template-columns: 1;
grid-template-rows: auto; grid-template-rows: auto;
gap: 8px; gap: 8px;
}
.intro-container,
.question-container {
max-width: 450px;
margin: 0 auto;
} }
.intro-content-header, .intro-content-header,
@ -291,12 +309,7 @@ main {
line-height: 1.4; line-height: 1.4;
padding: 1.6rem 1.2rem; padding: 1.6rem 1.2rem;
& em {
font-style: normal;
background-color: var(--clr-text-highlight);
padding: 1px 2px;
margin-right: -2px;
}
& input[type=radio] { & input[type=radio] {
position: absolute; position: absolute;
@ -312,15 +325,39 @@ main {
} }
} }
.question-result {
.question-container {
& em {
font-style: normal;
background-color: var(--clr-text-highlight);
padding: 1px 2px;
margin-right: -2px;
}
& strong {
font-weight: 700;
}
}
.question-result, .result-stats {
background-color: var(--clr-medium-yellow); background-color: var(--clr-medium-yellow);
border-radius: 1.2rem; border-radius: 1.2rem;
font-size: var(--fs-base); font-size: var(--fs-base);
line-height: 1.4; line-height: 1.4;
padding: 1.6rem 1.2rem; padding: 1.6rem 1.2rem;
}
& strong {
font-weight: 700;
.result-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.8rem;
& a {
background-color: var(--clr-medium-yellow);
border-color: var(--clr-medium-yellow);
color: var(--clr-black)
} }
} }
@ -353,8 +390,20 @@ main {
font-size: 4rem; font-size: 4rem;
} }
} }
}
.result-msg {
background-color: var(--clr-white);
border-radius: 1.2rem;
font-size: var(--fs-base);
line-height: 1.4;
padding: 2.0rem 1.2rem;
& h1 {
font-size: var(--fs-3xl);
line-height: 1.1;
margin: 0 0 0.4em 0;
}
} }
@ -395,7 +444,7 @@ label.question-answer {
} }
main { main {
margin: 2rem 3rem;
margin: 0 2rem 3rem 2rem;
} }
footer { footer {


+ 1
- 0
app/controllers/answers_controller.rb View File

@ -10,6 +10,7 @@ class AnswersController < ApplicationController
respond_to do |format| respond_to do |format|
if @answer.save if @answer.save
current_player.update_answer_cache
format.html { redirect_to url_for(controller: 'questions', action: 'answer', id: params[:id]) } format.html { redirect_to url_for(controller: 'questions', action: 'answer', id: params[:id]) }
else else
format.html { render 'questions/show', status: :unprocessable_entity } format.html { render 'questions/show', status: :unprocessable_entity }


+ 9
- 2
app/controllers/concerns/quiz_helper_methods.rb View File

@ -10,7 +10,8 @@ module QuizHelperMethods
:question, :question,
:questions_size, :questions_size,
:question_index, :question_index,
:player_question_answer
:player_question_answer,
:result_node
end end
@ -19,7 +20,11 @@ private
def questions def questions
@questions ||= Node.at_depth(1).viewable.ordered.to_a
@questions ||= Node.at_depth(1).tmpl_article.viewable.ordered.to_a
end
def result_node
@result_node ||= Node.at_depth(1).tmpl_list.viewable.first
end end
@ -63,4 +68,6 @@ private
def player_present? def player_present?
current_player.present? current_player.present?
end end
end end

+ 29
- 0
app/controllers/questions_controller.rb View File

@ -16,9 +16,38 @@ class QuestionsController < ApplicationController
end end
def result
not_found if result_node.blank? or current_player.answers.count < questions.size
planet_score = 0
current_player.answers.ordered.each_with_index do |answer, i|
case i
when 0, 3
planet_score += 1 if answer.value == 0
else
planet_score += 1 if answer.value == 1
end
end
attachment_index = case
when planet_score < 2
0 # People
when planet_score > 3
1 # Planet
else
2 # Balanced
end
@result_attachment = result_node.attachments.offset(attachment_index).first
@stats_attachment = result_node.attachments.offset(3).first
end
end end

+ 2
- 0
app/models/answer.rb View File

@ -6,4 +6,6 @@ class Answer < ApplicationRecord
validates :value, presence: true validates :value, presence: true
validates :value, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } validates :value, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }
scope :ordered, -> { joins(:node).order('nodes.position ASC, nodes.ancestry ASC') }
end end

+ 28
- 0
app/models/player.rb View File

@ -4,4 +4,32 @@ class Player < ApplicationRecord
has_many :answers, dependent: :destroy has_many :answers, dependent: :destroy
def update_answer_cache
self.update_column(:answer_cache, self.answers.ordered.pluck(:value))
end
def stats
total_with_five = Player.where("array_length(answer_cache, 1) = 5")
.where.not(id: self.id)
.count
matching_answers = Player.where(answer_cache: self.answer_cache)
.where("array_length(answer_cache, 1) = 5")
.where.not(id: self.id)
.count
# Calculate percentage
if total_with_five > 0
percentage = (matching_answers.to_f / total_with_five) * 100
percentage_string = percentage.round.to_s
else
percentage_string = "0"
end
percentage_string
end
end end

+ 5
- 1
app/views/questions/answer.html.erb View File

@ -23,6 +23,10 @@
<%= @question_answer.last.body.html_safe %> <%= @question_answer.last.body.html_safe %>
</div> </div>
<%= link_to t('next_question'), url_for(controller: 'questions', action: 'show', id: question_index), class: 'button__base' %>
<% if question == questions.last %>
<%= link_to t('see_results'), url_for(controller: 'questions', action: 'result'), class: 'button__base' %>
<% else %>
<%= link_to t('next_question'), url_for(controller: 'questions', action: 'show', id: question_index), class: 'button__base' %>
<% end %>
</div> </div>

+ 28
- 0
app/views/questions/result.html.erb View File

@ -0,0 +1,28 @@
<%-
content_for :title, result_node.page_title.blank? ? result_node.title : result_node.page_title
content_for :meta_description, result_node.page_description
%>
<div class="question-container">
<div class="question-step">
<div><%= t 'results' %></div>
</div>
<div class="result-msg">
<%= @result_attachment&.body&.sub("&lt;name&gt;", html_escape(current_player.name)).html_safe %>
</div>
<div class="result-stats">
<%= @stats_attachment&.body&.sub("&lt;score&gt;", current_player.stats).html_safe %>
</div>
<div class="result-actions">
<%= link_to t('read_more'), "#", class: 'button__base' %>
<%= button_tag t('share_on_story'), type: 'button', class: 'button__base' %>
</div>
</div>

+ 4
- 0
config/locales/en.yml View File

@ -9,6 +9,10 @@ en:
submit: Submit submit: Submit
next_question: Next question next_question: Next question
of_people_worldwide_think_just_lik_you: of people worldwide think like you. of_people_worldwide_think_just_lik_you: of people worldwide think like you.
see_results: See results
results: Results
read_more: Read more
share_on_story: Share on story
languages: languages:


+ 2
- 0
config/routes.rb View File

@ -59,6 +59,8 @@ Rails.application.routes.draw do
get 'q/:id/answer', to: 'questions#answer' get 'q/:id/answer', to: 'questions#answer'
get 'q/:id', to: 'questions#show' get 'q/:id', to: 'questions#show'
get 'result', to: 'questions#result'
get '', to: 'languages#show' get '', to: 'languages#show'
# get '*url', to: 'site#page', constraints: lambda { |req| req.path.exclude?('storage') } # get '*url', to: 'site#page', constraints: lambda { |req| req.path.exclude?('storage') }


+ 3
- 0
db/migrate/20250429085114_create_players.rb View File

@ -4,8 +4,11 @@ class CreatePlayers < ActiveRecord::Migration[8.0]
t.text :name t.text :name
t.text :locale t.text :locale
t.integer :answer_cache, array: true, default: []
t.timestamps t.timestamps
t.index :answer_cache, using: :gin
end end
end end
end end

+ 2
- 0
db/schema.rb View File

@ -117,8 +117,10 @@ ActiveRecord::Schema[8.0].define(version: 2025_04_29_121602) do
create_table "players", force: :cascade do |t| create_table "players", force: :cascade do |t|
t.text "name" t.text "name"
t.text "locale" t.text "locale"
t.integer "answer_cache", default: [], array: true
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["answer_cache"], name: "index_players_on_answer_cache", using: :gin
end end
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|


Loading…
Cancel
Save