decidim-forms 0.30.3 → 0.31.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -10
  3. data/app/cells/decidim/forms/matrix_readonly/show.erb +1 -1
  4. data/app/cells/decidim/forms/matrix_readonly_cell.rb +3 -3
  5. data/app/cells/decidim/forms/question_readonly/show.erb +5 -5
  6. data/app/cells/decidim/forms/question_readonly/title_and_description.erb +3 -3
  7. data/app/cells/decidim/forms/response_readonly_cell.rb +9 -0
  8. data/app/cells/decidim/forms/step_navigation/show.erb +3 -3
  9. data/app/cells/decidim/forms/step_navigation_cell.rb +3 -3
  10. data/app/commands/decidim/forms/admin/update_questions.rb +6 -6
  11. data/app/commands/decidim/forms/{answer_questionnaire.rb → response_questionnaire.rb} +35 -35
  12. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +12 -12
  13. data/app/controllers/decidim/forms/admin/concerns/{has_questionnaire_answers.rb → has_questionnaire_responses.rb} +23 -19
  14. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +38 -33
  15. data/app/forms/decidim/forms/admin/display_condition_form.rb +14 -14
  16. data/app/forms/decidim/forms/admin/question_form.rb +3 -3
  17. data/app/forms/decidim/forms/admin/{answer_option_form.rb → response_option_form.rb} +3 -3
  18. data/app/forms/decidim/forms/questionnaire_form.rb +8 -9
  19. data/app/forms/decidim/forms/{answer_choice_form.rb → response_choice_form.rb} +5 -5
  20. data/app/forms/decidim/forms/{answer_form.rb → response_form.rb} +9 -9
  21. data/app/helpers/decidim/forms/admin/application_helper.rb +2 -2
  22. data/app/helpers/decidim/forms/admin/concerns/{has_questionnaire_answers_pagination_helper.rb → has_questionnaire_responses_pagination_helper.rb} +4 -4
  23. data/app/helpers/decidim/forms/admin/concerns/{has_questionnaire_answers_url_helper.rb → has_questionnaire_responses_url_helper.rb} +5 -5
  24. data/app/helpers/decidim/forms/admin/questionnaire_responses_helper.rb +32 -0
  25. data/app/helpers/decidim/forms/application_helper.rb +1 -2
  26. data/app/jobs/decidim/forms/{export_questionnaire_answers_job.rb → export_questionnaire_responses_job.rb} +5 -5
  27. data/app/models/decidim/forms/display_condition.rb +20 -20
  28. data/app/models/decidim/forms/question.rb +14 -13
  29. data/app/models/decidim/forms/question_matrix_row.rb +1 -1
  30. data/app/models/decidim/forms/questionnaire.rb +11 -6
  31. data/app/models/decidim/forms/{answer.rb → response.rb} +9 -9
  32. data/app/models/decidim/forms/response_choice.rb +22 -0
  33. data/app/models/decidim/forms/{answer_option.rb → response_option.rb} +5 -5
  34. data/app/packs/entrypoints/decidim_forms_admin.js +3 -3
  35. data/app/packs/src/decidim/forms/admin/collapsible_questions.js +12 -10
  36. data/app/packs/src/decidim/forms/admin/forms.js +35 -35
  37. data/app/packs/src/decidim/forms/admin/{publish_answers_buttons.js → publish_responses_buttons.js} +12 -12
  38. data/app/packs/src/decidim/forms/display_conditions.component.js +12 -12
  39. data/app/packs/src/decidim/forms/forms.js +8 -29
  40. data/app/packs/stylesheets/decidim/forms/forms.scss +2 -2
  41. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +13 -13
  42. data/app/presenters/decidim/forms/admin/{questionnaire_answer_presenter.rb → questionnaire_response_presenter.rb} +15 -15
  43. data/app/presenters/decidim/forms/admin_log/question_presenter.rb +3 -3
  44. data/app/presenters/decidim/forms/{answer_option_presenter.rb → response_option_presenter.rb} +2 -2
  45. data/app/queries/decidim/forms/questionnaire_participant.rb +5 -5
  46. data/app/queries/decidim/forms/questionnaire_participants.rb +6 -6
  47. data/app/queries/decidim/forms/questionnaire_user_responses.rb +32 -0
  48. data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +9 -9
  49. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +2 -2
  50. data/app/views/decidim/forms/admin/questionnaires/_matrix_row.html.erb +3 -3
  51. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +21 -11
  52. data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +13 -41
  53. data/app/views/decidim/forms/admin/questionnaires/{_answer_option.html.erb → _response_option.html.erb} +7 -7
  54. data/app/views/decidim/forms/admin/questionnaires/_response_option_template.html.erb +7 -0
  55. data/app/views/decidim/forms/admin/questionnaires/_separator.html.erb +11 -1
  56. data/app/views/decidim/forms/admin/questionnaires/_title_and_description.html.erb +12 -2
  57. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +1 -1
  58. data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +8 -8
  59. data/app/views/decidim/forms/admin/questionnaires/responses/index.html.erb +80 -0
  60. data/app/views/decidim/forms/admin/questionnaires/responses/show.html.erb +43 -0
  61. data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +22 -26
  62. data/app/views/decidim/forms/questionnaires/_questionnaire_readonly.html.erb +8 -3
  63. data/app/views/decidim/forms/questionnaires/_response.html.erb +61 -0
  64. data/app/views/decidim/forms/questionnaires/edit.html.erb +2 -2
  65. data/app/views/decidim/forms/questionnaires/responses/_files.html.erb +1 -0
  66. data/app/views/decidim/forms/questionnaires/responses/_long_response.html.erb +3 -0
  67. data/app/views/decidim/forms/questionnaires/{answers → responses}/_matrix_multiple.html.erb +16 -15
  68. data/app/views/decidim/forms/questionnaires/{answers → responses}/_matrix_single.html.erb +17 -16
  69. data/app/views/decidim/forms/questionnaires/responses/_multiple_option.html.erb +26 -0
  70. data/app/views/decidim/forms/questionnaires/responses/_separator.html.erb +1 -0
  71. data/app/views/decidim/forms/questionnaires/responses/_short_response.html.erb +3 -0
  72. data/app/views/decidim/forms/questionnaires/responses/_single_option.html.erb +33 -0
  73. data/app/views/decidim/forms/questionnaires/responses/_sorting.html.erb +26 -0
  74. data/app/views/decidim/forms/questionnaires/responses/_title_and_description.html.erb +1 -0
  75. data/app/views/decidim/forms/questionnaires/show.html.erb +10 -10
  76. data/config/assets.rb +2 -2
  77. data/config/locales/ar.yml +2 -22
  78. data/config/locales/bg.yml +10 -36
  79. data/config/locales/ca-IT.yml +80 -74
  80. data/config/locales/ca.yml +80 -74
  81. data/config/locales/cs.yml +79 -76
  82. data/config/locales/de.yml +79 -72
  83. data/config/locales/el.yml +10 -36
  84. data/config/locales/en.yml +90 -84
  85. data/config/locales/es-MX.yml +82 -76
  86. data/config/locales/es-PY.yml +82 -76
  87. data/config/locales/es.yml +80 -74
  88. data/config/locales/eu.yml +78 -72
  89. data/config/locales/fi-plain.yml +78 -72
  90. data/config/locales/fi.yml +76 -70
  91. data/config/locales/fr-CA.yml +77 -68
  92. data/config/locales/fr.yml +77 -68
  93. data/config/locales/ga-IE.yml +4 -7
  94. data/config/locales/gl.yml +4 -22
  95. data/config/locales/hu.yml +4 -22
  96. data/config/locales/id-ID.yml +2 -22
  97. data/config/locales/it.yml +8 -40
  98. data/config/locales/ja.yml +87 -81
  99. data/config/locales/lb.yml +8 -36
  100. data/config/locales/lt.yml +10 -36
  101. data/config/locales/lv.yml +4 -22
  102. data/config/locales/nl.yml +10 -36
  103. data/config/locales/no.yml +10 -36
  104. data/config/locales/pl.yml +10 -36
  105. data/config/locales/pt-BR.yml +10 -36
  106. data/config/locales/pt.yml +8 -36
  107. data/config/locales/ro-RO.yml +29 -51
  108. data/config/locales/ru.yml +2 -9
  109. data/config/locales/sk.yml +2 -22
  110. data/config/locales/sl.yml +0 -5
  111. data/config/locales/sv.yml +89 -55
  112. data/config/locales/tr-TR.yml +8 -36
  113. data/config/locales/val-ES.yml +2 -0
  114. data/config/locales/zh-CN.yml +8 -36
  115. data/config/locales/zh-TW.yml +10 -36
  116. data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
  117. data/db/migrate/20250314150250_rename_answer_to_response_in_decidim_forms.rb +30 -0
  118. data/db/migrate/20250319130003_change_question_types_in_questions.rb +14 -0
  119. data/lib/decidim/api/question_matrix_row_type.rb +13 -0
  120. data/lib/decidim/api/question_type.rb +4 -3
  121. data/lib/decidim/api/questionnaire_type.rb +1 -0
  122. data/lib/decidim/api/response_option_type.rb +13 -0
  123. data/lib/decidim/exporters/form_pdf.rb +33 -33
  124. data/lib/decidim/forms/api.rb +2 -1
  125. data/lib/decidim/forms/{download_your_data_user_answers_serializer.rb → download_your_data_user_responses_serializer.rb} +3 -3
  126. data/lib/decidim/forms/engine.rb +2 -2
  127. data/lib/decidim/forms/test/factories.rb +24 -24
  128. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +176 -176
  129. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_responses.rb +159 -0
  130. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -19
  131. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +44 -44
  132. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +10 -10
  133. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +43 -140
  134. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +4 -4
  135. data/lib/decidim/forms/test.rb +1 -1
  136. data/lib/decidim/forms/user_responses_serializer.rb +110 -0
  137. data/lib/decidim/forms/version.rb +1 -1
  138. data/lib/decidim/forms.rb +2 -2
  139. metadata +48 -45
  140. data/app/cells/decidim/forms/answer_readonly_cell.rb +0 -9
  141. data/app/helpers/decidim/forms/admin/questionnaire_answers_helper.rb +0 -30
  142. data/app/models/decidim/forms/answer_choice.rb +0 -22
  143. data/app/queries/decidim/forms/questionnaire_user_answers.rb +0 -32
  144. data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +0 -7
  145. data/app/views/decidim/forms/admin/questionnaires/answers/index.html.erb +0 -49
  146. data/app/views/decidim/forms/admin/questionnaires/answers/show.html.erb +0 -43
  147. data/app/views/decidim/forms/questionnaires/_answer.html.erb +0 -61
  148. data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +0 -1
  149. data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +0 -3
  150. data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +0 -25
  151. data/app/views/decidim/forms/questionnaires/answers/_separator.html.erb +0 -1
  152. data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +0 -3
  153. data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +0 -32
  154. data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +0 -26
  155. data/app/views/decidim/forms/questionnaires/answers/_title_and_description.html.erb +0 -1
  156. data/lib/decidim/api/answer_option_type.rb +0 -13
  157. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +0 -149
  158. data/lib/decidim/forms/user_answers_serializer.rb +0 -105
  159. /data/app/cells/decidim/forms/{answer_readonly → response_readonly}/show.erb +0 -0
@@ -13,7 +13,7 @@ import createDisplayConditions from "src/decidim/forms/display_conditions.compon
13
13
  import createMaxChoicesAlertComponent from "src/decidim/forms/max_choices_alert.component"
14
14
  import { preventUnload } from "src/decidim/utilities/dom"
15
15
 
16
- $(() => {
16
+ document.addEventListener("turbo:load", () => {
17
17
  $(".js-radio-button-collection, .js-check-box-collection").each((idx, el) => {
18
18
  createOptionAttachedInputs({
19
19
  wrapperField: $(el),
@@ -22,7 +22,7 @@ $(() => {
22
22
  });
23
23
  });
24
24
 
25
- $.unique($(".js-check-box-collection").parents(".answer")).each((idx, el) => {
25
+ $.unique($(".js-check-box-collection").parents(".response")).each((idx, el) => {
26
26
  const maxChoices = $(el).data("max-choices");
27
27
  if (maxChoices) {
28
28
  createMaxChoicesAlertComponent({
@@ -35,39 +35,18 @@ $(() => {
35
35
  }
36
36
  });
37
37
 
38
- document.querySelectorAll(".js-sortable-check-box-collection").forEach((el) => {
38
+ document.querySelectorAll(".js-sortable-check-box-collection").forEach((el) => new DragonDrop(el, {
39
+ handle: false,
40
+ item: ".js-collection-input"
41
+ }));
39
42
 
40
- /**
41
- * Due to a bug reported in https://github.com/decidim/decidim/issues/15191
42
- * we have to listen to the `drag` event and prevent the scrolling
43
- * and enabling it back again after it.
44
- */
45
-
46
- let preventScroll = function(event) {
47
- event.preventDefault();
48
- }
49
-
50
- el.addEventListener("touchmove", (event) => {
51
- preventScroll(event);
52
- }, { passive: false });
53
-
54
- el.addEventListener("touchend", () => {
55
- el.removeEventListener("touchmove", preventScroll)
56
- });
57
-
58
- return new DragonDrop(el, {
59
- handle: false,
60
- item: ".js-collection-input"
61
- });
62
- });
63
-
64
- $(".answer-questionnaire .question[data-conditioned='true']").each((idx, el) => {
43
+ $(".response-questionnaire .question[data-conditioned='true']").each((idx, el) => {
65
44
  createDisplayConditions({
66
45
  wrapperField: $(el)
67
46
  });
68
47
  });
69
48
 
70
- const form = document.querySelector("form.answer-questionnaire");
49
+ const form = document.querySelector("form.response-questionnaire");
71
50
  if (form) {
72
51
  const safePath = form.dataset.safePath.split("?")[0];
73
52
  let exitUrl = "";
@@ -1,4 +1,4 @@
1
- .answer-questionnaire {
1
+ .response-questionnaire {
2
2
  @apply border-t-2 border-background pt-8;
3
3
 
4
4
  &__step {
@@ -22,7 +22,7 @@
22
22
  }
23
23
 
24
24
  &__question-label {
25
- @apply text-black text-xl font-semibold relative before:content-[attr(data-answer-idx)] before:w-6 before:h-6 md:before:absolute md:before:-left-4 md:before:-translate-x-full before:inline-flex before:justify-center before:rounded-full before:bg-background before:text-lg before:text-gray-2 before:font-semibold;
25
+ @apply text-black text-xl font-semibold relative before:content-[attr(data-response-idx)] before:w-6 before:h-6 md:before:absolute md:before:-left-4 md:before:-translate-x-full before:inline-flex before:justify-center before:rounded-full before:bg-background before:text-lg before:text-gray-2 before:font-semibold;
26
26
  }
27
27
 
28
28
  &__question-description {
@@ -19,7 +19,7 @@ module Decidim
19
19
  participant.ip_hash || "-"
20
20
  end
21
21
 
22
- def answered_at
22
+ def responded_at
23
23
  participant.created_at
24
24
  end
25
25
 
@@ -30,23 +30,23 @@ module Decidim
30
30
  end
31
31
 
32
32
  def status
33
- I18n.t(registered? ? "registered" : "unregistered", scope: "decidim.forms.user_answers_serializer")
33
+ I18n.t(registered? ? "registered" : "unregistered", scope: "decidim.forms.user_responses_serializer")
34
34
  end
35
35
 
36
- def answers
37
- siblings.map { |answer| QuestionnaireAnswerPresenter.new(answer:) }
36
+ def responses
37
+ siblings.map { |response| QuestionnaireResponsePresenter.new(response:) }
38
38
  end
39
39
 
40
- def first_short_answer
41
- short = siblings.where(decidim_forms_questions: { question_type: %w(short_answer) })
40
+ def first_short_response
41
+ short = siblings.where(decidim_forms_questions: { question_type: %w(short_response) })
42
42
  short.first
43
43
  end
44
44
 
45
45
  def completion
46
- with_body = siblings.where(decidim_forms_questions: { question_type: %w(short_answer long_answer) })
46
+ with_body = siblings.where(decidim_forms_questions: { question_type: %w(short_response long_response) })
47
47
  .where.not(body: "").count
48
- with_choices = siblings.where.not(decidim_forms_questions: { question_type: %w(short_answer long_answer) })
49
- .where("decidim_forms_answers.id IN (SELECT decidim_answer_id FROM decidim_forms_answer_choices)").count
48
+ with_choices = siblings.where.not(decidim_forms_questions: { question_type: %w(short_response long_response) })
49
+ .where("decidim_forms_responses.id IN (SELECT decidim_response_id FROM decidim_forms_response_choices)").count
50
50
 
51
51
  (with_body + with_choices).to_f / questionnaire.questions.not_separator.not_title_and_description.count * 100
52
52
  end
@@ -54,10 +54,10 @@ module Decidim
54
54
  private
55
55
 
56
56
  def siblings
57
- Answer.not_separator
58
- .not_title_and_description
59
- .where(questionnaire:, session_token: participant.session_token)
60
- .joins(:question).order("decidim_forms_questions.position ASC")
57
+ Response.not_separator
58
+ .not_title_and_description
59
+ .where(questionnaire:, session_token: participant.session_token)
60
+ .joins(:question).order("decidim_forms_questions.position ASC")
61
61
  end
62
62
  end
63
63
  end
@@ -4,15 +4,15 @@ module Decidim
4
4
  module Forms
5
5
  module Admin
6
6
  #
7
- # Presenter for questionnaire answer
7
+ # Presenter for questionnaire response
8
8
  #
9
- class QuestionnaireAnswerPresenter < SimpleDelegator
9
+ class QuestionnaireResponsePresenter < SimpleDelegator
10
10
  delegate :content_tag, :safe_join, :link_to, :number_to_human_size, to: :view_context
11
11
 
12
12
  include Decidim::TranslatableAttributes
13
13
 
14
- def answer
15
- __getobj__.fetch(:answer)
14
+ def response
15
+ __getobj__.fetch(:response)
16
16
  end
17
17
 
18
18
  def view_context
@@ -20,22 +20,22 @@ module Decidim
20
20
  end
21
21
 
22
22
  def question
23
- translated_attribute(answer.question.body)
23
+ translated_attribute(response.question.body)
24
24
  end
25
25
 
26
26
  def body
27
- return answer.body if answer.body.present?
28
- return attachments if answer.attachments.any?
29
- return "-" if answer.choices.empty?
27
+ return response.body if response.body.present?
28
+ return attachments if response.attachments.any?
29
+ return "-" if response.choices.empty?
30
30
 
31
- choices = answer.choices.map do |choice|
31
+ choices = response.choices.map do |choice|
32
32
  {
33
- answer_option_body: choice.try(:answer_option).try(:translated_body),
33
+ response_option_body: choice.try(:response_option).try(:translated_body),
34
34
  choice_body: body_or_custom_body(choice)
35
35
  }
36
36
  end
37
37
 
38
- return choice(choices.first) if answer.question.question_type == "single_option"
38
+ return choice(choices.first) if response.question.question_type == "single_option"
39
39
 
40
40
  content_tag(:ul) do
41
41
  safe_join(choices.map { |c| choice(c) })
@@ -44,7 +44,7 @@ module Decidim
44
44
 
45
45
  def attachments
46
46
  content_tag(:ul) do
47
- safe_join(answer.attachments.map { |a| pretty_attachment(a) })
47
+ safe_join(response.attachments.map { |a| pretty_attachment(a) })
48
48
  end
49
49
  end
50
50
 
@@ -57,7 +57,7 @@ module Decidim
57
57
  link_to(attachment.url, target: "_blank", rel: "noopener noreferrer") do
58
58
  content_tag(:span) do
59
59
  translated_attribute(attachment.title).presence ||
60
- I18n.t("download_attachment", scope: "decidim.forms.questionnaire_answer_presenter")
60
+ I18n.t("download_attachment", scope: "decidim.forms.questionnaire_response_presenter")
61
61
  end + " " + content_tag(:small) do
62
62
  "#{attachment.file_type} #{number_to_human_size(attachment.file_size)}"
63
63
  end
@@ -73,9 +73,9 @@ module Decidim
73
73
  end
74
74
 
75
75
  def render_body_for(choice_hash)
76
- return choice_hash[:answer_option_body] if choice_hash[:choice_body].blank?
76
+ return choice_hash[:response_option_body] if choice_hash[:choice_body].blank?
77
77
 
78
- "#{choice_hash[:answer_option_body]} (#{choice_hash[:choice_body]})"
78
+ "#{choice_hash[:response_option_body]} (#{choice_hash[:choice_body]})"
79
79
  end
80
80
 
81
81
  def body_or_custom_body(choice)
@@ -15,11 +15,11 @@ module Decidim
15
15
  class QuestionPresenter < Decidim::Log::BasePresenter
16
16
  private
17
17
 
18
- # i18n-tasks-use t("decidim.forms.admin_log.question.publish_answers")
19
- # i18n-tasks-use t("decidim.forms.admin_log.question.unpublish_answers")
18
+ # i18n-tasks-use t("decidim.forms.admin_log.question.publish_responses")
19
+ # i18n-tasks-use t("decidim.forms.admin_log.question.unpublish_responses")
20
20
  def action_string
21
21
  case action
22
- when "publish_answers", "unpublish_answers"
22
+ when "publish_responses", "unpublish_responses"
23
23
  "decidim.forms.admin_log.question.#{action}"
24
24
  else
25
25
  super
@@ -3,9 +3,9 @@
3
3
  module Decidim
4
4
  module Forms
5
5
  #
6
- # Decorator for answer_options
6
+ # Decorator for response_options
7
7
  #
8
- class AnswerOptionPresenter < SimpleDelegator
8
+ class ResponseOptionPresenter < SimpleDelegator
9
9
  include Decidim::TranslationsHelper
10
10
 
11
11
  def translated_body
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Decidim
4
4
  module Forms
5
- # A class used to collect user answers for a questionnaire
5
+ # A class used to collect user responses for a questionnaire
6
6
  class QuestionnaireParticipant < Decidim::Query
7
7
  # Syntactic sugar to initialize the class and return the queried objects.
8
8
  #
@@ -23,12 +23,12 @@ module Decidim
23
23
 
24
24
  # Returns query with participant info
25
25
  def query
26
- answers.select(:session_token, :decidim_user_id, :ip_hash).first
26
+ responses.select(:session_token, :decidim_user_id, :ip_hash).first
27
27
  end
28
28
 
29
- # Finds the participant's answers.
30
- def answers
31
- Answer.where(questionnaire: @questionnaire, session_token: @token)
29
+ # Finds the participant's responses.
30
+ def responses
31
+ Response.where(questionnaire: @questionnaire, session_token: @token)
32
32
  end
33
33
  end
34
34
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Decidim
4
4
  module Forms
5
- # A class used to collect user answers for a questionnaire
5
+ # A class used to collect user responses for a questionnaire
6
6
  class QuestionnaireParticipants < Decidim::Query
7
7
  # Syntactic sugar to initialize the class and return the queried objects.
8
8
  #
@@ -18,12 +18,12 @@ module Decidim
18
18
  @questionnaire = questionnaire
19
19
  end
20
20
 
21
- # Finds all Answers for the questionnaire (unique session_tokens).
22
- # Because exporters only have access to the Answers this
21
+ # Finds all Responses for the questionnaire (unique session_tokens).
22
+ # Because exporters only have access to the Responses this
23
23
  # is used as an indirect way to access the participants
24
24
  # (see #participants and #participant)
25
25
  def query
26
- Answer.where(questionnaire: @questionnaire)
26
+ Response.where(questionnaire: @questionnaire)
27
27
  end
28
28
 
29
29
  def participant(session_token)
@@ -31,8 +31,8 @@ module Decidim
31
31
  end
32
32
 
33
33
  def participants
34
- subquery = query.select("DISTINCT ON (decidim_forms_answers.session_token) decidim_forms_answers.*")
35
- Answer.select("*").from(subquery).order(:created_at)
34
+ subquery = query.select("DISTINCT ON (decidim_forms_responses.session_token) decidim_forms_responses.*")
35
+ Response.select("*").from(subquery).order(:created_at)
36
36
  end
37
37
 
38
38
  def count_participants
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Forms
5
+ # A class used to collect user responses for a questionnaire
6
+ class QuestionnaireUserResponses < Decidim::Query
7
+ # Syntactic sugar to initialize the class and return the queried objects.
8
+ #
9
+ # questionnaire - a Questionnaire object
10
+ def self.for(questionnaire)
11
+ new(questionnaire).query
12
+ end
13
+
14
+ # Initializes the class.
15
+ #
16
+ # questionnaire = a Questionnaire object
17
+ def initialize(questionnaire)
18
+ @questionnaire = questionnaire
19
+ end
20
+
21
+ # Finds and group responses by user for each questionnaire's question.
22
+ def query
23
+ responses = Response.not_separator
24
+ .not_title_and_description
25
+ .joins(:question)
26
+ .where(questionnaire: @questionnaire)
27
+
28
+ responses.sort_by { |response| response.question.position.to_i }.group_by { |a| a.user || a.session_token }.values
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,13 +1,13 @@
1
1
  <% display_condition = form.object %>
2
2
 
3
- <div class="card questionnaire-question-display-condition">
3
+ <div class="card questionnaire-question-display-condition m-4">
4
4
  <div class="card-divider">
5
5
  <h2 class="card-title">
6
6
  <span><%= t(".display_condition") %></span>
7
7
  <% if editable %>
8
- <button class="button button__sm button__transparent-secondary small alert remove-display-condition button--title">
8
+ <button class="button button__xs button__transparent-secondary small alert remove-display-condition button--title">
9
9
  <%= icon("delete-bin-line") %>
10
- <%= t(".remove") %>
10
+ <span class="hidden md:block"><%= t(".remove") %></span>
11
11
  </button>
12
12
  <% end %>
13
13
  </h2>
@@ -27,7 +27,7 @@
27
27
  options_for_select(display_condition.questions_for_select(questionnaire, question.id), selected: display_condition.decidim_condition_question_id),
28
28
  { prompt: t(".select_condition_question"), label: t(".condition_question") },
29
29
  disabled: !editable,
30
- data: { url: answer_options_url(id: question.id) }
30
+ data: { url: response_options_url(id: question.id) }
31
31
  )
32
32
  %>
33
33
  </div>
@@ -41,14 +41,14 @@
41
41
  )
42
42
  %>
43
43
  </div>
44
- <div class="row column questionnaire-question-display-condition-answer-option">
44
+ <div class="row column questionnaire-question-display-condition-response-option">
45
45
  <%=
46
46
  form.select(
47
- :decidim_answer_option_id,
48
- options_from_collection_for_select(display_condition.answer_options, :id, :translated_body, selected: display_condition.decidim_answer_option_id),
49
- { prompt: t(".select_answer_option"), label: t(".answer_option") },
47
+ :decidim_response_option_id,
48
+ options_from_collection_for_select(display_condition.response_options, :id, :translated_body, selected: display_condition.decidim_response_option_id),
49
+ { prompt: t(".select_response_option"), label: t(".response_option") },
50
50
  disabled: !editable,
51
- data: { selected: display_condition.decidim_answer_option_id }
51
+ data: { selected: display_condition.decidim_response_option_id }
52
52
  )
53
53
  %>
54
54
  </div>
@@ -5,10 +5,10 @@
5
5
  <%= form.translated :text_field, :title, autofocus: true, aria: { label: :title } %>
6
6
  </div>
7
7
  <div class="row column">
8
- <%= form.translated :editor, :description, toolbar: :full, lines: 30, label: t("models.components.description", scope: "decidim.forms.admin"), aria: { label: :description } %>
8
+ <%= form.translated :editor, :description, toolbar: :full, lines: 8, label: t("models.components.description", scope: "decidim.forms.admin"), aria: { label: :description } %>
9
9
  </div>
10
10
  <div class="row column">
11
- <%= form.translated :editor, :tos, toolbar: :content, lines: 10, label: t("models.components.tos", scope: "decidim.forms.admin"), aria: { label: :tos } %>
11
+ <%= form.translated :editor, :tos, toolbar: :content, lines: 8, label: t("models.components.tos", scope: "decidim.forms.admin"), aria: { label: :tos } %>
12
12
  </div>
13
13
  </div>
14
14
  </div>
@@ -1,13 +1,13 @@
1
1
  <% matrix_row = form.object %>
2
2
 
3
- <div class="card questionnaire-question-matrix-row">
3
+ <div class="card questionnaire-question-matrix-row mt-4">
4
4
  <div class="card-divider">
5
5
  <h2 class="card-title">
6
6
  <span><%= t(".matrix_row") %></span>
7
7
  <% if editable %>
8
- <button class="button button__sm button__transparent-secondary small alert remove-matrix-row button--title mb-2">
8
+ <button class="button button__xs button__transparent-secondary small alert remove-matrix-row button--title mb-2">
9
9
  <%= icon("delete-bin-line") %>
10
- <%= t(".remove") %>
10
+ <span class="hidden md:block"><%= t(".remove") %></span>
11
11
  </button>
12
12
  <% end %>
13
13
  </h2>
@@ -1,7 +1,7 @@
1
1
  <% question = form.object %>
2
2
  <% is_expanded = question.errors.any? %>
3
3
  <div class="card questionnaire-question" id="accordion-<%= id %>-field">
4
- <div class="form__wrapper" data-component="accordion">
4
+ <div class="form__wrapper" data-controller="accordion">
5
5
  <div class="card-divider">
6
6
  <h2 class="card-title flex items-center">
7
7
  <span>
@@ -23,16 +23,26 @@
23
23
  </button>
24
24
 
25
25
  <% if editable %>
26
+ <button class="button button__xs button__transparent-secondary small alert move-up-question button--title">
27
+ <%= icon("arrow-up-line") %>
28
+ <span class="hidden md:block"><%= t(".up") %></span>
29
+ </button>
30
+
31
+ <button class="button button__xs button__transparent-secondary small alert move-down-question button--title">
32
+ <%= icon("arrow-down-line") %>
33
+ <span class="hidden md:block"><%= t(".down") %></span>
34
+ </button>
35
+
26
36
  <button class="button button__xs button__transparent-secondary small alert remove-question button--title">
27
37
  <%= icon("delete-bin-line") %>
28
- <%= t(".remove") %>
38
+ <span class="hidden md:block"><%= t(".remove") %></span>
29
39
  </button>
30
40
  <% end %>
31
41
  </span>
32
42
  </h2>
33
43
  </div>
34
44
 
35
- <div id="panel-<%= id %>-question-card" class="panel-question-card card-section collapsible <%= "panel-error" if is_expanded %>">
45
+ <div id="panel-<%= id %>-question-card" class="panel-question-card card-section collapsible <%= "panel-error" if is_expanded %>" aria-hidden="<%= is_expanded ? "false" : "true" %>">
36
46
  <div class="row column">
37
47
  <%=
38
48
  form.translated(
@@ -108,23 +118,23 @@
108
118
  </div>
109
119
 
110
120
  <% if editable %>
111
- <button class="button button__sm button__secondary add-matrix-row"><%= t(".add_matrix_row") %></button>
121
+ <button class="button button__xs button__transparent-secondary mt-4 add-matrix-row"><%= t(".add_matrix_row") %></button>
112
122
  <% end %>
113
123
  </div>
114
124
  </div>
115
125
 
116
- <div class="questionnaire-question-answer-options" data-template="<%= answer_option_template_selector %>">
117
- <div class="questionnaire-question-answer-options-list">
118
- <% question.answer_options.each do |answer_option| %>
119
- <%= fields_for "questions[questions][#{question.to_param}][answer_options][]", answer_option do |answer_option_form| %>
120
- <%= render "decidim/forms/admin/questionnaires/answer_option", form: answer_option_form, question:, editable: %>
126
+ <div class="questionnaire-question-response-options" data-template="<%= response_option_template_selector %>">
127
+ <div class="questionnaire-question-response-options-list">
128
+ <% question.response_options.each do |response_option| %>
129
+ <%= fields_for "questions[questions][#{question.to_param}][response_options][]", response_option do |response_option_form| %>
130
+ <%= render "decidim/forms/admin/questionnaires/response_option", form: response_option_form, question:, editable: %>
121
131
  <% end %>
122
132
  <% end %>
123
133
  </div>
124
134
 
125
135
  <% if editable %>
126
136
  <div class="row column">
127
- <button type="button" class="button button__sm button__secondary mt-4 add-answer-option"><%= t(".add_answer_option") %></button>
137
+ <button type="button" class="button button__xs button__transparent-secondary mt-4 add-response-option"><%= t(".add_response_option") %></button>
128
138
  </div>
129
139
  <% end %>
130
140
  </div>
@@ -152,7 +162,7 @@
152
162
  <% if editable %>
153
163
  <% disabled = !question.persisted? %>
154
164
  <div class="row column">
155
- <button <%= "disabled" if disabled %> title="<%= disabled ? t(".add_display_condition_info") : t(".add_display_condition_info") %>" class="button button__sm button__secondary mt-4 add-display-condition"><%= t(".add_display_condition") %></button>
165
+ <button <%= "disabled" if disabled %> title="<%= disabled ? t(".add_display_condition_info") : t(".add_display_condition_info") %>" class="button button__xs button__transparent-secondary mt-4 add-display-condition"><%= t(".add_display_condition") %></button>
156
166
  </div>
157
167
  <% end %>
158
168
  </div>
@@ -1,11 +1,12 @@
1
1
  <div class="questionnaire-questions form__wrapper">
2
- <div class="row column text-center my-4">
3
- <button type="button" class="button button__sm button__secondary collapse-all"><%= t(".collapse") %></button>
4
- <button type="button" class="button button__sm button__secondary expand-all"><%= t(".expand") %></button>
2
+ <div class="row column text-right my-4">
3
+ <button type="button" class="button button__sm button__text-secondary collapse-all"><%= t(".collapse") %></button>
4
+ |
5
+ <button type="button" class="button button__sm button__text-secondary expand-all"><%= t(".expand") %></button>
5
6
  </div>
6
7
 
7
8
  <% if questionnaire.questions_editable? %>
8
- <% if questionnaire.answers.any? && !questionnaire.published? %>
9
+ <% if questionnaire.responses.any? && !questionnaire.published? %>
9
10
  <%= cell("decidim/announcement", t(".unpublished_warning"), callout_class: "warning" ) %>
10
11
  <% end %>
11
12
 
@@ -15,7 +16,7 @@
15
16
  form: question_form,
16
17
  id: tabs_id_for_question(blank_question),
17
18
  editable: questionnaire.questions_editable?,
18
- answer_option_template_selector: "#answer-option-template-dummy",
19
+ response_option_template_selector: "#response-option-template-dummy",
19
20
  display_condition_template_selector: "#display-condition-template-dummy",
20
21
  matrix_row_template_selector: "#matrix-row-template-dummy" %>
21
22
  </script>
@@ -31,15 +32,15 @@
31
32
  id: tabs_id_for_question(blank_question),
32
33
  editable: questionnaire.questions_editable? %>
33
34
  </script>
34
- <%= render "decidim/forms/admin/questionnaires/answer_option_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "answer-option-template-dummy" %>
35
+ <%= render "decidim/forms/admin/questionnaires/response_option_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "response-option-template-dummy" %>
35
36
  <%= render "decidim/forms/admin/questionnaires/display_condition_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "display-condition-template-dummy" %>
36
37
  <%= render "decidim/forms/admin/questionnaires/matrix_row_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "matrix-row-template-dummy" %>
37
38
  <% end %>
38
39
  <% else %>
39
- <%= cell("decidim/announcement", t(".already_answered_warning"), callout_class: "warning" ) %>
40
+ <%= cell("decidim/announcement", t(".already_responded_warning"), callout_class: "warning" ) %>
40
41
  <% end %>
41
42
 
42
- <div class="questionnaire-questions-list flex flex-col py-6 gap-6 last:pb-0" data-draggable-table data-sort-url="#" id="questionnaire-questions-list">
43
+ <div class="questionnaire-questions-list flex flex-col py-6 gap-6 last:pb-0">
43
44
  <% @form.questions.each_with_index do |question, index| %>
44
45
  <%= fields_for "questions[questions][]", question do |question_form| %>
45
46
  <% if question.separator? %>
@@ -58,10 +59,10 @@
58
59
  id: tabs_id_for_question(question),
59
60
  editable: questionnaire.questions_editable?,
60
61
  display_condition_template_selector: "#display-condition-template-#{index}",
61
- answer_option_template_selector: "#answer-option-template-#{index}",
62
+ response_option_template_selector: "#response-option-template-#{index}",
62
63
  matrix_row_template_selector: "#matrix-row-template-#{index}" %>
63
64
  <%= render "decidim/forms/admin/questionnaires/display_condition_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "display-condition-template-#{index}" %>
64
- <%= render "decidim/forms/admin/questionnaires/answer_option_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "answer-option-template-#{index}" %>
65
+ <%= render "decidim/forms/admin/questionnaires/response_option_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "response-option-template-#{index}" %>
65
66
  <%= render "decidim/forms/admin/questionnaires/matrix_row_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "matrix-row-template-#{index}" %>
66
67
  <% end %>
67
68
  <% end %>
@@ -72,38 +73,9 @@
72
73
  <%= append_javascript_pack_tag "decidim_forms_admin" %>
73
74
 
74
75
  <% if questionnaire.questions_editable? %>
75
- <script>
76
- document.addEventListener("DOMContentLoaded", function () {
76
+ <script>
77
+ document.addEventListener("turbo:load", function () {
77
78
  window.Decidim.createEditableForm();
78
-
79
- // Function to initialize the sortable functionality
80
- function initializeSortable() {
81
- const container = document.querySelector("#questionnaire-questions-list");
82
- const questionCards = container?.querySelectorAll(".card.questionnaire-question");
83
-
84
- if (!container || !questionCards?.length) return;
85
-
86
- questionCards.forEach(card => {
87
- card.setAttribute("draggable", "true");
88
- card.setAttribute("role", "option");
89
- card.setAttribute("aria-grabbed", "false");
90
- });
91
-
92
- window.Decidim?.createSortableList?.("#questionnaire-questions-list");
93
- }
94
-
95
- // Initialize on load and when new options such as questions etc are added
96
- initializeSortable();
97
-
98
- const observer = new MutationObserver(() => {
99
- clearTimeout(observer.timer);
100
- observer.timer = setTimeout(initializeSortable, 500);
101
- });
102
-
103
- const container = document.querySelector("#questionnaire-questions-list");
104
- if (container) {
105
- observer.observe(container, { childList: true, subtree: true });
106
- }
107
79
  });
108
80
  </script>
109
81
  <% end %>
@@ -1,13 +1,13 @@
1
- <% answer_option = form.object %>
1
+ <% response_option = form.object %>
2
2
 
3
- <div class="card questionnaire-question-answer-option">
3
+ <div class="card questionnaire-question-response-option m-4">
4
4
  <div class="card-divider">
5
5
  <h2 class="card-title">
6
- <span><%= t(".answer_option") %></span>
6
+ <span><%= t(".response_option") %></span>
7
7
  <% if editable %>
8
- <button class="button button__sm button__transparent-secondary small alert remove-answer-option button--title mb-2">
8
+ <button class="button button__xs button__transparent-secondary small alert remove-response-option button--title mb-2">
9
9
  <%= icon("delete-bin-line") %>
10
- <%= t(".remove") %>
10
+ <span class="hidden md:block"><%= t(".remove") %></span>
11
11
  </button>
12
12
  <% end %>
13
13
  </h2>
@@ -19,7 +19,7 @@
19
19
  form.translated(
20
20
  :text_field,
21
21
  :body,
22
- tabs_id: tabs_id_for_question_answer_option(question, answer_option),
22
+ tabs_id: tabs_id_for_question_response_option(question, response_option),
23
23
  label: t(".statement"),
24
24
  disabled: !editable
25
25
  )
@@ -37,7 +37,7 @@
37
37
  </div>
38
38
  </div>
39
39
 
40
- <% if answer_option.persisted? %>
40
+ <% if response_option.persisted? %>
41
41
  <%= form.hidden_field :id, disabled: !editable %>
42
42
  <% end %>
43
43
 
@@ -0,0 +1,7 @@
1
+ <% question = form.object %>
2
+
3
+ <script type="text/template" class="decidim-response-option-template decidim-template" id="<%= template_id %>">
4
+ <%= fields_for "questions[questions][#{question.to_param}][response_options][]", blank_response_option do |response_option_form| %>
5
+ <%= render "decidim/forms/admin/questionnaires/response_option", form: response_option_form, question:, editable: %>
6
+ <% end %>
7
+ </script>