diff --git a/app/components/polls/questions/answers_component.html.erb b/app/components/polls/questions/answers_component.html.erb index de84bcd7f..c73247ec2 100644 --- a/app/components/polls/questions/answers_component.html.erb +++ b/app/components/polls/questions/answers_component.html.erb @@ -15,7 +15,8 @@ remote: true, title: t("poll_questions.show.vote_answer", answer: question_answer.title), class: "button secondary hollow", - "aria-pressed": false do %> + "aria-pressed": false, + disabled: disable_answer?(question_answer) do %> <%= question_answer.title %> <% end %> <% end %> diff --git a/app/components/polls/questions/answers_component.rb b/app/components/polls/questions/answers_component.rb index b21459a97..0509d8fa7 100644 --- a/app/components/polls/questions/answers_component.rb +++ b/app/components/polls/questions/answers_component.rb @@ -18,6 +18,10 @@ class Polls::Questions::AnswersComponent < ApplicationComponent user_answers.find_by(answer: question_answer.title) end + def disable_answer?(question_answer) + question.multiple? && user_answers.count == question.max_votes + end + private def user_answers diff --git a/app/components/polls/questions/question_component.html.erb b/app/components/polls/questions/question_component.html.erb index 5fd7eeb8b..3cd99a1b4 100644 --- a/app/components/polls/questions/question_component.html.erb +++ b/app/components/polls/questions/question_component.html.erb @@ -3,6 +3,12 @@ <%= question.title %> + <% if question.votation_type.present? %> + + <%= t("poll_questions.description.#{question.vote_type}", maximum: question.max_votes) %> + + <% end %> +
<%= render Polls::Questions::AnswersComponent.new(question) %>
diff --git a/app/controllers/polls/questions_controller.rb b/app/controllers/polls/questions_controller.rb index 3731aa2f9..a21acc9bc 100644 --- a/app/controllers/polls/questions_controller.rb +++ b/app/controllers/polls/questions_controller.rb @@ -5,9 +5,7 @@ class Polls::QuestionsController < ApplicationController has_orders %w[most_voted newest oldest], only: :show def answer - answer = @question.answers.find_or_initialize_by(author: current_user) - - answer.answer = params[:answer] + answer = @question.find_or_initialize_user_answer(current_user, params[:answer]) answer.save_and_record_voter_participation respond_to do |format| @@ -15,7 +13,7 @@ class Polls::QuestionsController < ApplicationController redirect_to request.referer end format.js do - render :answer + render :answers end end end diff --git a/app/models/concerns/questionable.rb b/app/models/concerns/questionable.rb index f7b20b8f4..1d0606fc6 100644 --- a/app/models/concerns/questionable.rb +++ b/app/models/concerns/questionable.rb @@ -10,4 +10,21 @@ module Questionable def unique? votation_type.nil? || votation_type.unique? end + + def find_or_initialize_user_answer(user, title) + answer = answers.find_or_initialize_by(find_by_attributes(user, title)) + answer.answer = title + answer + end + + private + + def find_by_attributes(user, title) + case vote_type + when "unique", nil + { author: user } + when "multiple" + { author: user, answer: title } + end + end end diff --git a/app/models/poll/answer.rb b/app/models/poll/answer.rb index 41d76e925..d9d86e9d6 100644 --- a/app/models/poll/answer.rb +++ b/app/models/poll/answer.rb @@ -38,6 +38,7 @@ class Poll::Answer < ApplicationRecord def max_votes return if !question || question&.unique? || persisted? + author.reload author.lock! if question.answers.by_author(author).count >= question.max_votes diff --git a/app/views/polls/questions/answer.js.erb b/app/views/polls/questions/answers.js.erb similarity index 100% rename from app/views/polls/questions/answer.js.erb rename to app/views/polls/questions/answers.js.erb diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 4a70c1a3e..afc277ef4 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -636,6 +636,9 @@ en: show: vote_answer: "Vote %{answer}" voted: "You have voted %{answer}" + description: + unique: "You can select a maximum of 1 answer." + multiple: "You can select a maximum of %{maximum} answers." proposal_notifications: new: title: "Send notification" diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index d731f4bd4..382b302e6 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -636,6 +636,9 @@ es: show: vote_answer: "Votar %{answer}" voted: "Has votado %{answer}" + description: + unique: "Puedes seleccionar un máximo de 1 respuesta." + multiple: "Puedes seleccionar un máximo de %{maximum} respuestas." proposal_notifications: new: title: "Enviar notificación" diff --git a/spec/components/polls/questions/answers_component_spec.rb b/spec/components/polls/questions/answers_component_spec.rb index 0b05953c2..a5460b83e 100644 --- a/spec/components/polls/questions/answers_component_spec.rb +++ b/spec/components/polls/questions/answers_component_spec.rb @@ -33,6 +33,20 @@ describe Polls::Questions::AnswersComponent do expect(page).to have_css "button[aria-pressed='true']", text: "Yes" end + it "renders disabled buttons when max votes is reached" do + user = create(:user, :verified) + question = create(:poll_question_multiple, :abc, max_votes: 2, author: user) + create(:poll_answer, author: user, question: question, answer: "Answer A") + create(:poll_answer, author: user, question: question, answer: "Answer C") + sign_in(user) + + render_inline Polls::Questions::AnswersComponent.new(question) + + expect(page).to have_button "You have voted Answer A" + expect(page).to have_button "Vote Answer B", disabled: true + expect(page).to have_button "You have voted Answer C" + end + it "when user is not signed in, renders answers links pointing to user sign in path" do render_inline Polls::Questions::AnswersComponent.new(question) diff --git a/spec/system/polls/votation_types_spec.rb b/spec/system/polls/votation_types_spec.rb new file mode 100644 index 000000000..51efb7f2c --- /dev/null +++ b/spec/system/polls/votation_types_spec.rb @@ -0,0 +1,69 @@ +require "rails_helper" + +describe "Poll Votation Type" do + let(:author) { create(:user, :level_two) } + + before do + login_as(author) + end + + scenario "Unique answer" do + question = create(:poll_question_unique, :yes_no) + + visit poll_path(question.poll) + + expect(page).to have_content "You can select a maximum of 1 answer." + expect(page).to have_content(question.title) + expect(page).to have_button("Vote Yes") + expect(page).to have_button("Vote No") + + within "#poll_question_#{question.id}_answers" do + click_button "Yes" + + expect(page).to have_button("You have voted Yes") + expect(page).to have_button("Vote No") + + click_button "No" + + expect(page).to have_button("Vote Yes") + expect(page).to have_button("You have voted No") + end + end + + scenario "Multiple answers" do + question = create(:poll_question_multiple, :abc, max_votes: 2) + visit poll_path(question.poll) + + expect(page).to have_content "You can select a maximum of 2 answers." + expect(page).to have_content(question.title) + expect(page).to have_button("Vote Answer A") + expect(page).to have_button("Vote Answer B") + expect(page).to have_button("Vote Answer C") + + within "#poll_question_#{question.id}_answers" do + click_button "Vote Answer A" + + expect(page).to have_button("You have voted Answer A") + + click_button "Vote Answer C" + + expect(page).to have_button("You have voted Answer C") + expect(page).to have_button("Vote Answer B", disabled: true) + + click_button "You have voted Answer A" + + expect(page).to have_button("Vote Answer A") + expect(page).to have_button("Vote Answer B") + + click_button "You have voted Answer C" + + expect(page).to have_button("Vote Answer C") + + click_button "Vote Answer B" + + expect(page).to have_button("You have voted Answer B") + expect(page).to have_button("Vote Answer A") + expect(page).to have_button("Vote Answer C") + end + end +end