decidim-forms 0.25.0.rc4 → 0.26.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/commands/decidim/forms/answer_questionnaire.rb +6 -2
  3. data/app/forms/decidim/forms/admin/question_form.rb +4 -0
  4. data/app/models/decidim/forms/answer.rb +1 -0
  5. data/app/models/decidim/forms/question.rb +7 -1
  6. data/app/packs/src/decidim/forms/admin/forms.js +2 -0
  7. data/app/presenters/decidim/forms/admin/questionnaire_answer_presenter.rb +19 -4
  8. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +5 -2
  9. data/app/queries/decidim/forms/questionnaire_user_answers.rb +4 -1
  10. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +12 -0
  11. data/app/views/decidim/forms/admin/questionnaires/_title_and_description.html.erb +80 -0
  12. data/app/views/decidim/forms/questionnaires/_answer.html.erb +10 -1
  13. data/app/views/decidim/forms/questionnaires/answers/_title_and_description.html.erb +1 -0
  14. data/app/views/decidim/forms/questionnaires/show.html.erb +8 -7
  15. data/config/locales/cs.yml +11 -0
  16. data/config/locales/en.yml +11 -0
  17. data/config/locales/es.yml +11 -0
  18. data/config/locales/eu.yml +92 -1
  19. data/config/locales/fi.yml +11 -0
  20. data/config/locales/fr-CA.yml +11 -0
  21. data/config/locales/fr.yml +11 -0
  22. data/config/locales/ga-IE.yml +52 -0
  23. data/config/locales/ja.yml +12 -1
  24. data/config/locales/lb-LU.yml +103 -0
  25. data/config/locales/lb.yml +178 -0
  26. data/config/locales/nl.yml +11 -0
  27. data/config/locales/pl.yml +5 -5
  28. data/config/locales/pt-BR.yml +1 -1
  29. data/config/locales/pt.yml +10 -0
  30. data/config/locales/ro-RO.yml +58 -58
  31. data/config/locales/val-ES.yml +18 -0
  32. data/lib/decidim/forms/engine.rb +4 -0
  33. data/lib/decidim/forms/test/factories.rb +12 -0
  34. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +18 -0
  35. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +36 -5
  36. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +98 -0
  37. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +8 -0
  38. data/lib/decidim/forms/user_answers_serializer.rb +41 -9
  39. data/lib/decidim/forms/version.rb +1 -1
  40. metadata +16 -12
@@ -4,13 +4,13 @@ ro:
4
4
  answer:
5
5
  body: Răspuns
6
6
  choices: Opțiuni
7
- selected_choices: Alegeri selectate
7
+ selected_choices: Opțiuni selectate
8
8
  question:
9
9
  max_choices: Numărul maxim de opțiuni
10
10
  question_type: Tip
11
11
  questionnaire_question:
12
- mandatory: Mandatory
13
- max_characters: Limita de caractere (lăsați la 0 dacă nu este limită)
12
+ mandatory: Obligatoriu
13
+ max_characters: Limita de caractere (lăsați la 0 dacă nu este nicio limită)
14
14
  errors:
15
15
  models:
16
16
  answer:
@@ -20,23 +20,23 @@ ro:
20
20
  body:
21
21
  too_long: este prea lung
22
22
  choices:
23
- missing: nu sunt complete
23
+ missing: nu sunt completate
24
24
  too_many: sunt prea multe
25
25
  questionnaire:
26
- request_invalid: A apărut o eroare la procesarea cererii. rugăm să încercați din nou
26
+ request_invalid: A apărut o eroare la procesarea cererii. Te rugăm să încerci din nou
27
27
  decidim:
28
28
  forms:
29
29
  admin:
30
30
  models:
31
31
  components:
32
32
  description: Descriere
33
- tos: Termenii serviciului
33
+ tos: Condiţii de utilizare
34
34
  questionnaires:
35
35
  actions:
36
36
  back: Înapoi la întrebări
37
- show: Arată răspunsurile
37
+ show: Afișează răspunsurile
38
38
  answer_option:
39
- answer_option: Opțiune răspuns
39
+ answer_option: Opțiune de răspuns
40
40
  free_text: Text liber
41
41
  remove: Elimină
42
42
  statement: Declarație
@@ -44,76 +44,76 @@ ro:
44
44
  actions:
45
45
  back: Înapoi la răspunsuri
46
46
  export: Exportă
47
- show: Arată răspunsurile
48
- empty: Încă nu există răspunsuri
47
+ show: Afişează răspunsurile
48
+ empty: Niciun răspuns încă
49
49
  export:
50
50
  answer:
51
51
  title: 'Răspuns #%{number}'
52
52
  export_response:
53
- title: chestionar_utilizator_răspunsuri_%{token}
53
+ title: survey_user_answers_%{token}
54
54
  index:
55
55
  title: "%{total} total răspunsuri"
56
56
  show:
57
57
  title: 'Răspuns #%{number}'
58
58
  display_condition:
59
- answer_option: Opțiune răspuns
59
+ answer_option: Opțiune de răspuns
60
60
  condition_question: Întrebare
61
61
  condition_type: Condiție
62
62
  condition_types:
63
- answered: Răspuns
64
- equal: Egal
63
+ answered: Răspunse
64
+ equal: Egal cu
65
65
  match: Include textul
66
- not_answered: Nu s-a răspuns
67
- not_equal: Nu este egal
66
+ not_answered: Fără răspuns
67
+ not_equal: Nu este egal cu
68
68
  condition_value: Text inclus
69
- display_condition: Condiție de afișare
70
- mandatory: Această condiție trebuie îndeplinită întotdeauna indiferent de statutul altor condiții
69
+ display_condition: Afișează condiția
70
+ mandatory: Această condiție trebuie îndeplinită întotdeauna indiferent de stadiul altor condiții
71
71
  remove: Elimină
72
- save_warning: Amintiţi-văsalvaţi formularul înainte de configurarea condiţiilor de afişare
73
- select_answer_option: Selectați opțiunea de răspuns
72
+ save_warning: Ține minte salvezi chestionarul înainte de configurarea condiţiilor de afişare
73
+ select_answer_option: Selectează opțiunea de răspuns
74
74
  select_condition_question: Selectează o întrebare
75
- select_condition_type: Selectați un tip de condiție
75
+ select_condition_type: Selectează un tip de condiție
76
76
  edit:
77
77
  save: Salvează
78
- title: Editare chestionar
78
+ title: Editează chestionarul
79
79
  form:
80
80
  add_question: Adaugă întrebare
81
81
  add_separator: Adaugă separator
82
- already_answered_warning: Formularul a primit deja un răspuns de la unii utilizatori astfel încât nu îi puteți modifica întrebările.
82
+ already_answered_warning: Au fost înregistrare deja câteva răspunsuri de la utilizatori pentru acest chestionar. De aceea, nu mai poți modifica întrebările.
83
83
  collapse: Restrânge toate întrebările
84
84
  expand: Extinde toate întrebările
85
- preview: Previzualizare
86
- title: Editare formular pentru %{questionnaire_for}
87
- unpublished_warning: Formularul nu este publicat. Puteți modifica întrebările, dar acest lucru va șterge răspunsurile curente.
85
+ preview: Previzualizează
86
+ title: Editează chestionarul pentru %{questionnaire_for}
87
+ unpublished_warning: Chestionarul nu este publicat. Poți modifica întrebările, dar această acțiune va duce la stergerea automată a răspunsurilor curente.
88
88
  matrix_row:
89
89
  matrix_row: Rând
90
90
  remove: Elimină
91
91
  statement: Declarație
92
92
  question:
93
- add_answer_option: Adaugă opțiune răspuns
94
- add_display_condition: Adăugați o condiție de afișare
95
- add_display_condition_info: Salvați formularul pentru a configura condițiile de afișare
93
+ add_answer_option: Adaugă opțiune de răspuns
94
+ add_display_condition: Adaugă condiție de afișare
95
+ add_display_condition_info: Salvează formularul pentru a configura condițiile de afișare
96
96
  add_matrix_row: Adaugă rând
97
97
  any: Oricare
98
98
  collapse: Restrânge
99
99
  description: Descriere
100
- down: Jos
100
+ down: Mergi în jos
101
101
  expand: Extinde
102
102
  question: Întrebare
103
103
  remove: Elimină
104
104
  statement: Declarație
105
- up: Sus
105
+ up: Mergi în sus
106
106
  separator:
107
- down: Jos
107
+ down: Mergi în jos
108
108
  remove: Elimină
109
109
  separator: Separator
110
- up: Sus
110
+ up: Mergi în sus
111
111
  update:
112
- invalid: A apărut o eroare la salvarea formularului.
113
- success: Formular salvat cu succes.
112
+ invalid: A apărut o eroare la salvarea chestionarului.
113
+ success: Chestionarul a fost salvat cu succes.
114
114
  errors:
115
115
  answer:
116
- body: Corpul nu poate fi gol
116
+ body: Conținutul nu poate fi gol
117
117
  files:
118
118
  extension_allowlist: 'Formate acceptate:'
119
119
  images:
@@ -121,58 +121,58 @@ ro:
121
121
  dimensions_info: 'Această imagine va fi:'
122
122
  processors:
123
123
  resize_and_pad: Redimensionat și padded la
124
- resize_to_fit: Redimensionat pentru a se potrivi
124
+ resize_to_fit: Redimensionată pentru a se potrivi
125
125
  question_types:
126
126
  files: Fișiere
127
127
  long_answer: Răspuns lung
128
- matrix_multiple: Matricea (opțiune multiplă)
129
- matrix_single: Matricea (opțiunea unică)
130
- multiple_option: Opțiune multiplă
128
+ matrix_multiple: Matrice (mai multe opțiuni)
129
+ matrix_single: Matrice (opțiune unică)
130
+ multiple_option: Mai multe opțiuni
131
131
  short_answer: Răspuns scurt
132
132
  single_option: Opțiune unică
133
133
  sorting: Sortare
134
134
  questionnaires:
135
135
  answer:
136
- invalid: A apărut o problemă cu răspunsul la formular.
136
+ invalid: A apărut o problemă la completarea chestionarului.
137
137
  max_choices_alert: Există prea multe alegeri selectate
138
- success: Formularul a răspuns cu succes.
138
+ success: Chestionarul a fost completat cu succes.
139
139
  question:
140
- max_choices: 'Max alegeri: %{n}'
140
+ max_choices: 'Număr maxim de alegeri: %{n}'
141
141
  show:
142
142
  answer_questionnaire:
143
- anonymous_user_message: <a href="%{sign_in_link}">Autentifică-te cu contul tău</a> sau <a href="%{sign_up_link}">înregistrează-te</a> pentru a răspunde la formular.
144
- title: Răspundeți la formular
143
+ anonymous_user_message: <a href="%{sign_in_link}">Autentifică-te cu contul tău</a> sau <a href="%{sign_up_link}">înregistrează-te</a> pentru a răspunde la chestionar.
144
+ title: Completează chestionarul
145
145
  current_step: Pasul %{step}
146
146
  of_total_steps: din %{total_steps}
147
147
  questionnaire_answered:
148
- body: Ați răspuns deja la acest formular.
149
- title: Răspuns deja
148
+ body: Ai completat deja la acest chestionar.
149
+ title: Un răspuns a fost deja trimis
150
150
  questionnaire_closed:
151
- body: Formularul este închis și nu se poate răspunde.
151
+ body: Chestionarul este închis și nu mai poate fi completat.
152
152
  title: Formular închis
153
153
  questionnaire_for_private_users:
154
- body: Formularul este disponibil doar pentru utilizatorii privați
155
- title: Formular închis
154
+ body: Chestionarul este disponibil doar pentru utilizatorii privați
155
+ title: Chestionar închis
156
156
  questionnaire_js_disabled:
157
- body: Unele dintre funcțiile acestui formular vor fi dezactivate. Pentru a îmbunătăți experiența, rugăm să activați JavaScript în browser-ul dvs.
157
+ body: Unele dintre funcționalitățile acestui chestionar vor fi dezactivate. Pentru a îți îmbunătăți experiența, te rugăm să activezi JavaScript în browser-ul tău.
158
158
  title: JavaScript este dezactivat
159
159
  questionnaire_not_published:
160
- body: Acest formular nu este publicat încă.
161
- tos_agreement: Prin participare acceptați termenii și condițiile sale de utilizare
160
+ body: Acest chestionar nu este încă publicat.
161
+ tos_agreement: Prin participare accepți Termenii și condițiile sale de utilizare
162
162
  step_navigation:
163
163
  show:
164
- are_you_sure: Această acțiune nu poate fi anulată și nu veți putea să editați răspunsurile. Sunteți sigur?
164
+ are_you_sure: Această acțiune nu poate fi anulată și nu vei putea să îți editezi răspunsurile. Sigur dorești asta?
165
165
  back: Înapoi
166
166
  continue: Continuă
167
- submit: Trimiteți
167
+ submit: Trimite
168
168
  user_answers_serializer:
169
169
  body: Răspuns
170
170
  completion: Finalizare
171
- created_at: Răspuns pornit
171
+ created_at: Răspuns completat la
172
172
  id: ID răspuns
173
- ip_hash: Hash IP
173
+ ip_hash: IP Hash
174
174
  question: Întrebare
175
175
  registered: Înregistrat
176
176
  session_token: Identificator utilizator
177
177
  unregistered: Neînregistrat
178
- user_status: Statusul utilizatorului
178
+ user_status: Stadiul utilizatorului
@@ -0,0 +1,18 @@
1
+ val:
2
+ decidim:
3
+ forms:
4
+ admin:
5
+ questionnaires:
6
+ form:
7
+ add_title_and_description: Afig títol i descripció
8
+ title_and_description:
9
+ collapse: Redueix
10
+ description: Descripció
11
+ down: Baixar
12
+ expand: Expandeix
13
+ remove: Elimina
14
+ title: Títol
15
+ title_and_description: Títol i descripció
16
+ up: Pujar
17
+ question_types:
18
+ title_and_description: Títol i descripció
@@ -11,6 +11,10 @@ module Decidim
11
11
  initializer "decidim_forms.add_cells_view_paths" do
12
12
  Cell::ViewModel.view_paths << File.expand_path("#{Decidim::Forms::Engine.root}/app/cells")
13
13
  end
14
+
15
+ initializer "decidim_forms.webpacker.assets_path" do
16
+ Decidim.register_assets_path File.expand_path("app/packs", root)
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -123,6 +123,10 @@ FactoryBot.define do
123
123
  trait :separator do
124
124
  question_type { :separator }
125
125
  end
126
+
127
+ trait :title_and_description do
128
+ question_type { :title_and_description }
129
+ end
126
130
  end
127
131
 
128
132
  factory :answer, class: "Decidim::Forms::Answer" do
@@ -144,6 +148,14 @@ FactoryBot.define do
144
148
  question { create(:questionnaire_question) }
145
149
  body { generate_localized_title }
146
150
  free_text { false }
151
+
152
+ trait :free_text_enabled do
153
+ free_text { true }
154
+ end
155
+
156
+ trait :free_text_disabled do
157
+ free_text { false }
158
+ end
147
159
  end
148
160
 
149
161
  factory :answer_choice, class: "Decidim::Forms::AnswerChoice" do
@@ -69,6 +69,24 @@ shared_examples_for "manage questionnaire answers" do
69
69
  expect(page).to have_content("User identifier")
70
70
  end
71
71
  end
72
+
73
+ context "when multiple answer choice" do
74
+ let(:first_type) { "multiple_option" }
75
+ let!(:answer1) { create :answer, questionnaire: questionnaire, question: first, body: nil }
76
+ let!(:answer_option) { create :answer_option, question: first }
77
+ let!(:answer_choice) { create :answer_choice, answer: answer1, answer_option: answer_option, body: translated(answer_option.body, locale: I18n.locale) }
78
+
79
+ before do
80
+ find_all("a.action-icon.action-icon--eye").first.click
81
+ end
82
+
83
+ it "shows the answers page with custom body" do
84
+ within "#answers" do
85
+ expect(page).to have_css("dt", text: translated(first.body))
86
+ expect(page).to have_css("li", text: translated(answer_option.body))
87
+ end
88
+ end
89
+ end
72
90
  end
73
91
 
74
92
  context "and managing individual answer page" do
@@ -4,20 +4,21 @@ require "spec_helper"
4
4
 
5
5
  shared_examples_for "add questions" do
6
6
  it "adds a few questions and separators to the questionnaire" do
7
- questions_body = ["This is the first question", "This is the second question"]
7
+ fields_body = ["This is the first question", "This is the second question", "This is the first title and description"]
8
8
 
9
9
  within "form.edit_questionnaire" do
10
10
  click_button "Add question"
11
11
  click_button "Add separator"
12
+ click_button "Add title and description"
12
13
  click_button "Add question"
13
14
 
14
- expect(page).to have_selector(".questionnaire-question", count: 3)
15
+ expect(page).to have_selector(".questionnaire-question", count: 4)
15
16
 
16
17
  expand_all_questions
17
18
 
18
- page.all(".questionnaire-question .collapsible").each_with_index do |question, idx|
19
- within question do
20
- fill_in find_nested_form_field_locator("body_en"), with: questions_body[idx]
19
+ page.all(".questionnaire-question .collapsible").each_with_index do |field, idx|
20
+ within field do
21
+ fill_in find_nested_form_field_locator("body_en"), with: fields_body[idx]
21
22
  end
22
23
  end
23
24
 
@@ -30,6 +31,7 @@ shared_examples_for "add questions" do
30
31
 
31
32
  expect(page).to have_selector("input[value='This is the first question']")
32
33
  expect(page).to have_selector("input[value='This is the second question']")
34
+ expect(page).to have_selector("input[value='This is the first title and description']")
33
35
  expect(page).to have_content("Separator #2")
34
36
  end
35
37
 
@@ -62,6 +64,35 @@ shared_examples_for "add questions" do
62
64
  expect(page).to have_selector("strong", text: "Superkalifragilistic description")
63
65
  end
64
66
 
67
+ it "adds a title-and-description" do
68
+ within "form.edit_questionnaire" do
69
+ click_button "Add title and description"
70
+ expand_all_questions
71
+
72
+ within ".questionnaire-question" do
73
+ fill_in find_nested_form_field_locator("body_en"), with: "Body"
74
+
75
+ fill_in_editor find_nested_form_field_locator("description_en", visible: false), with: "<strong>Superkalifragilistic description</strong>"
76
+ end
77
+
78
+ click_button "Save"
79
+ end
80
+
81
+ expect(page).to have_admin_callout("successfully")
82
+
83
+ component.update!(
84
+ step_settings: {
85
+ component.participatory_space.active_step.id => {
86
+ allow_answers: true
87
+ }
88
+ }
89
+ )
90
+
91
+ visit questionnaire_public_path
92
+
93
+ expect(page).to have_selector("strong", text: "Superkalifragilistic description")
94
+ end
95
+
65
96
  it "adds a question with answer options" do
66
97
  question_body = ["This is the first question", "This is the second question"]
67
98
  answer_options_body = [
@@ -118,6 +118,104 @@ shared_examples_for "update questions" do
118
118
  end
119
119
  end
120
120
 
121
+ context "when a questionnaire has a title and description" do
122
+ let!(:question) { create(:questionnaire_question, :title_and_description, questionnaire: questionnaire, body: title_and_description_body) }
123
+
124
+ before do
125
+ visit questionnaire_edit_path
126
+ expand_all_questions
127
+ end
128
+
129
+ it "modifies the question when the information is valid" do
130
+ within "form.edit_questionnaire" do
131
+ within ".questionnaire-question" do
132
+ fill_in "questionnaire_questions_#{question.id}_body_en", with: "Modified title and description"
133
+ end
134
+
135
+ click_button "Save"
136
+ end
137
+
138
+ expect(page).to have_admin_callout("successfully")
139
+
140
+ visit_questionnaire_edit_path_and_expand_all
141
+
142
+ expect(page).to have_selector("input[value='Modified title and description']")
143
+ expect(page).to have_no_selector("input[value='This is the first title and description']")
144
+ end
145
+
146
+ it "re-renders the form when the information is invalid and displays errors" do
147
+ expand_all_questions
148
+
149
+ within "form.edit_questionnaire" do
150
+ within ".questionnaire-question" do
151
+ fill_in "questionnaire_questions_#{question.id}_body_en", with: ""
152
+ end
153
+
154
+ click_button "Save"
155
+ end
156
+
157
+ expand_all_questions
158
+
159
+ expect(page).to have_admin_callout("There was a problem saving")
160
+ expect(page).to have_content("can't be blank", count: 1)
161
+ expect(page).to have_selector("input[value='']")
162
+ expect(page).to have_no_selector("input[value='This is the first title and description']")
163
+ end
164
+
165
+ it "preserves deleted status across submission failures" do
166
+ within "form.edit_questionnaire" do
167
+ within ".questionnaire-question" do
168
+ click_button "Remove"
169
+ end
170
+ end
171
+
172
+ click_button "Add question"
173
+
174
+ click_button "Save"
175
+
176
+ expect(page).to have_selector(".questionnaire-question", count: 1)
177
+
178
+ within ".questionnaire-question" do
179
+ expect(page).to have_selector(".card-title", text: "#1")
180
+ expect(page).to have_no_button("Up")
181
+ end
182
+ end
183
+
184
+ it "removes the question" do
185
+ within "form.edit_questionnaire" do
186
+ within ".questionnaire-question" do
187
+ click_button "Remove"
188
+ end
189
+
190
+ click_button "Save"
191
+ end
192
+
193
+ expect(page).to have_admin_callout("successfully")
194
+
195
+ visit questionnaire_edit_path
196
+
197
+ within "form.edit_questionnaire" do
198
+ expect(page).to have_selector(".questionnaire-question", count: 0)
199
+ end
200
+ end
201
+
202
+ it "cannot be moved up" do
203
+ within "form.edit_questionnaire" do
204
+ within ".questionnaire-question" do
205
+ expect(page).to have_no_button("Up")
206
+ end
207
+ end
208
+ end
209
+
210
+ it "cannot be moved down" do
211
+ within "form.edit_questionnaire" do
212
+ within ".questionnaire-question" do
213
+ expect(page).to have_no_button("Down")
214
+ end
215
+ end
216
+ end
217
+ end
218
+
121
219
  context "when a questionnaire has an existing question with answer options" do
122
220
  let!(:question) do
123
221
  create(
@@ -16,6 +16,14 @@ shared_examples_for "manage questionnaires" do
16
16
  }
17
17
  end
18
18
 
19
+ let(:title_and_description_body) do
20
+ {
21
+ en: "Este es el primer separador de texto",
22
+ ca: "Aquest és el primer separador de text",
23
+ es: "Esta es la primera pregunta"
24
+ }
25
+ end
26
+
19
27
  it "updates the questionnaire" do
20
28
  visit questionnaire_edit_path
21
29
 
@@ -14,15 +14,14 @@ module Decidim
14
14
 
15
15
  # Public: Exports a hash with the serialized data for the user answers.
16
16
  def serialize
17
- @answers.each_with_index.inject({}) do |serialized, (answer, idx)|
18
- serialized.update(
19
- answer_translated_attribute_name(:id) => answer.session_token,
20
- answer_translated_attribute_name(:created_at) => answer.created_at.to_s(:db),
21
- answer_translated_attribute_name(:ip_hash) => answer.ip_hash,
22
- answer_translated_attribute_name(:user_status) => answer_translated_attribute_name(answer.decidim_user_id.present? ? "registered" : "unregistered"),
23
- "#{idx + 1}. #{translated_attribute(answer.question.body)}" => normalize_body(answer)
24
- )
17
+ answers_hash = hash_for(@answers.first)
18
+ answers_hash.merge!(questions_hash)
19
+
20
+ @answers.each do |answer|
21
+ answers_hash[translated_question_key(answer.question.position, answer.question.body)] = normalize_body(answer)
25
22
  end
23
+
24
+ answers_hash
26
25
  end
27
26
 
28
27
  private
@@ -30,6 +29,33 @@ module Decidim
30
29
  attr_reader :answers
31
30
  alias resource answers
32
31
 
32
+ def hash_for(answer)
33
+ {
34
+ answer_translated_attribute_name(:id) => answer&.session_token,
35
+ answer_translated_attribute_name(:created_at) => answer&.created_at&.to_s(:db),
36
+ answer_translated_attribute_name(:ip_hash) => answer&.ip_hash,
37
+ answer_translated_attribute_name(:user_status) => answer_translated_attribute_name(answer&.decidim_user_id.present? ? "registered" : "unregistered")
38
+ }
39
+ end
40
+
41
+ def questions_hash
42
+ return {} if questionnaire&.questions.blank?
43
+
44
+ questionnaire.questions.each.inject({}) do |serialized, question|
45
+ serialized.update(
46
+ translated_question_key(question.position, question.body) => ""
47
+ )
48
+ end
49
+ end
50
+
51
+ def questionnaire
52
+ @answers.first&.questionnaire
53
+ end
54
+
55
+ def translated_question_key(idx, body)
56
+ "#{idx + 1}. #{translated_attribute(body)}"
57
+ end
58
+
33
59
  def normalize_body(answer)
34
60
  answer.body ||
35
61
  normalize_attachments(answer) ||
@@ -47,7 +73,7 @@ module Decidim
47
73
  normalize_matrix_choices(answer, choices)
48
74
  else
49
75
  choices.map do |choice|
50
- choice.try(:custom_body) || choice.try(:body)
76
+ format_free_text_for choice
51
77
  end
52
78
  end
53
79
  end
@@ -68,6 +94,12 @@ module Decidim
68
94
  def answer_translated_attribute_name(attribute)
69
95
  I18n.t(attribute.to_sym, scope: "decidim.forms.user_answers_serializer")
70
96
  end
97
+
98
+ def format_free_text_for(choice)
99
+ return choice.try(:body) if choice.try(:custom_body).blank?
100
+
101
+ "#{choice.try(:body)} (#{choice.try(:custom_body)})"
102
+ end
71
103
  end
72
104
  end
73
105
  end
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-forms version.
5
5
  module Forms
6
6
  def self.version
7
- "0.25.0.rc4"
7
+ "0.26.0.rc1"
8
8
  end
9
9
  end
10
10
  end