Skip to content
Merged

0.388.0 #1861

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -107,28 +107,28 @@ GEM
aws-sdk-ses (~> 1, >= 1.50.0)
aws-sdk-sesv2 (~> 1, >= 1.34.0)
aws-eventstream (1.3.2)
aws-partitions (1.1090.0)
aws-sdk-core (3.222.2)
aws-partitions (1.1096.0)
aws-sdk-core (3.223.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.99.0)
aws-sdk-kms (1.100.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sdk-rails (5.1.0)
aws-sdk-core (~> 3)
railties (>= 7.1.0)
aws-sdk-s3 (1.183.0)
aws-sdk-s3 (1.185.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sdk-ses (1.82.0)
aws-sdk-ses (1.83.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sdk-sesv2 (1.74.0)
aws-sdk-sesv2 (1.75.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.11.0)
Expand Down Expand Up @@ -186,7 +186,7 @@ GEM
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
concurrent-ruby (1.3.5)
connection_pool (2.5.1)
connection_pool (2.5.3)
crass (1.0.6)
csv (3.3.4)
database_cleaner (2.1.0)
Expand Down Expand Up @@ -219,7 +219,7 @@ GEM
railties (>= 5.0.0)
faker (3.5.1)
i18n (>= 1.8.11, < 2)
faraday (2.13.0)
faraday (2.13.1)
faraday-net_http (>= 2.0, < 3.5)
json
logger
Expand Down Expand Up @@ -280,7 +280,7 @@ GEM
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (2.10.2)
json (2.11.3)
json-jwt (1.16.7)
activesupport (>= 4.2)
aes_key_wrap
Expand Down Expand Up @@ -327,7 +327,7 @@ GEM
mime-types (3.6.2)
logger
mime-types-data (~> 3.2015)
mime-types-data (3.2025.0415)
mime-types-data (3.2025.0429)
mini_magick (5.2.0)
benchmark
logger
Expand All @@ -336,11 +336,11 @@ GEM
minitest (5.25.5)
msgpack (1.8.0)
multi_json (1.15.0)
multi_xml (0.7.1)
multi_xml (0.7.2)
bigdecimal (~> 3.1)
net-http (0.6.0)
uri
net-imap (0.5.7)
net-imap (0.5.8)
date
net-protocol
net-pop (0.1.2)
Expand All @@ -349,7 +349,7 @@ GEM
timeout
net-smtp (0.5.1)
net-protocol
newrelic_rpm (9.18.0)
newrelic_rpm (9.19.0)
nio4r (2.7.4)
nokogiri (1.18.8)
mini_portile2 (~> 2.8.2)
Expand Down Expand Up @@ -407,14 +407,14 @@ GEM
pry (0.15.2)
coderay (~> 1.1)
method_source (~> 1.0)
psych (5.2.3)
psych (5.2.4)
date
stringio
public_suffix (6.0.1)
public_suffix (6.0.2)
puma (6.6.0)
nio4r (~> 2.0)
racc (1.8.1)
rack (3.1.13)
rack (3.1.14)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-cors (2.0.2)
Expand All @@ -423,7 +423,7 @@ GEM
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
rack-session (2.1.0)
rack-session (2.1.1)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rack-test (2.2.0)
Expand Down Expand Up @@ -493,24 +493,24 @@ GEM
rolify (6.0.1)
rspec-core (3.13.3)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.3)
rspec-expectations (3.13.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.2)
rspec-mocks (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-rails (7.1.1)
actionpack (>= 7.0)
activesupport (>= 7.0)
railties (>= 7.0)
rspec-rails (8.0.0)
actionpack (>= 7.2)
activesupport (>= 7.2)
railties (>= 7.2)
rspec-core (~> 3.13)
rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13)
rspec-support (~> 3.13)
rspec-support (3.13.2)
rspec-support (3.13.3)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.75.3)
rubocop (1.75.4)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
Expand Down Expand Up @@ -555,7 +555,7 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
sidekiq (8.0.2)
sidekiq (8.0.3)
connection_pool (>= 2.5.0)
json (>= 2.9.0)
logger (>= 1.6.2)
Expand Down
1 change: 1 addition & 0 deletions app/controllers/admin/forms_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def permissions
def questions
@form.warn_about_not_too_many_questions
@form.ensure_a11_v2_format if @form.kind == "a11_v2"
@form.ensure_a11_v2_radio_format if @form.kind == "a11_v2_radio"
ensure_form_manager(form: @form) unless @form.template?
@questions = @form.ordered_questions
end
Expand Down
40 changes: 38 additions & 2 deletions app/models/form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def self.filtered_forms(user, aasm_state)
def self.kinds
[
"a11",
"a11_v2", # launched fall 2023
"a11_v2", # launched Fall 2023
"a11_v2_radio", # launched May 2025
"a11_yes_no",
"open_ended",
"other", # TODO: deprecate in favor of custom,
Expand Down Expand Up @@ -289,7 +290,7 @@ def self.send_inactive_form_emails_since(days_ago)
def self.find_inactive_forms_since(days_ago)
min_time = Time.now - days_ago.days
max_time = Time.now - (days_ago - 1).days
Form.published.where("last_response_created_at BETWEEN ? AND ?", min_time, max_time)
Form.non_templates.published.where("last_response_created_at BETWEEN ? AND ?", min_time, max_time)
end

def deployable_form?
Expand Down Expand Up @@ -734,6 +735,41 @@ def ensure_a11_v2_format
end
end

def ensure_a11_v2_radio_format
question_1 = self.ordered_questions.find { |q| q.answer_field == "answer_01" }
if question_1.question_type != 'radio_buttons'
errors.add(:base, "The question for `answer_01` must be a Radio Buttons component with 5 options, with values 1-5")
end

# ensure the form has the 4 required questions
required_elements = ["answer_01", "answer_02", "answer_03", "answer_04"]
unless contains_elements?(questions.collect(&:answer_field), required_elements)
errors.add(:base, "The A-11 v2 form must have questions for #{required_elements.to_sentence}")
end

# ensure the positive indicators include ease and effectiveness
question_2 = self.ordered_questions.find { |q| q.answer_field == "answer_02" }
question_options = question_2.question_options

question_option_values = question_options.collect(&:value)
required_options = ["effectiveness", "ease"]
missing_options = required_options - question_option_values
if missing_options.any?
errors.add(:base, "The question options for Question 2 must include: #{missing_options.join(', ')}")
end

# ensure the positive indicators include ease and effectiveness
question_3 = self.ordered_questions.find { |q| q.answer_field == "answer_03" }
question_options = question_3.question_options

question_option_values = question_options.collect(&:value)
required_options = ["effectiveness", "ease"]
missing_options = required_options - question_option_values
if missing_options.any?
errors.add(:base, "The question options for Question 3 must include: #{missing_options.join(', ')}")
end
end

def warn_about_not_too_many_questions
if questions.size > 12
errors.add(:base, "Touchpoints supports a maximum of 20 questions. There are currently #{questions_count} questions. Fewer questions tend to yield higher response rates.")
Expand Down
52 changes: 52 additions & 0 deletions app/views/components/_form_a11_v2_radio_script.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Assumes: 4 questions:
// 1. 5 radio buttons with values 1-5
// 2. positive checkbox indicators
// 3. negative checkbox indicators
// 4. open text
// Hides the 2nd and 3rd questions to start
// reveals 2 when selecting thumbs up
// reveals 3 when selecting thumbs down
<%
question_1 = form.ordered_questions.find { |q| q.answer_field == "answer_01"}
question_2 = form.ordered_questions.find { |q| q.answer_field == "answer_02"}
question_3 = form.ordered_questions.find { |q| q.answer_field == "answer_03"}
%>

document.addEventListener('onTouchpointsFormLoaded', function(e) {
const formElement = e.detail.formComponent.formElement();
const q2_container = formElement.querySelector("#<%= dom_id(question_2) %>");
const q3_container = formElement.querySelector("#<%= dom_id(question_3) %>");

function hideQ2() {
q2_container.style.display = 'none';
}
function showQ2() {
q2_container.style.display = 'block';
}

function hideQ3() {
q3_container.style.display = 'none';
}
function showQ3() {
q3_container.style.display = 'block';
}

function showAndHideQuestions(selectedOption) {
if (selectedOption === "1" || selectedOption === "2" || selectedOption === "3") {
hideQ2()
showQ3()
} else if (selectedOption === "4" || selectedOption === "5") {
showQ2()
hideQ3()
}
}

formElement.querySelectorAll('input[name="<%= question_1.ui_selector %>"]').forEach((radio) => {
radio.addEventListener('change', (event) => {
showAndHideQuestions(event.target.value);
});
});

hideQ2()
hideQ3()
})
14 changes: 10 additions & 4 deletions app/views/components/forms/question_types/_radio_buttons.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
<div class="question-options">
<% question.question_options.each_with_index do |option, index| %>
<% @option_id = dom_id(option) %>
<div class="radio-button usa-radio question-option"
<div
class="radio-button usa-radio question-option"
data-id="<%= option.id %>"
<%- if question.help_text.present? %>
aria-describedby="<%= "question-id-#{question.id}-help-text" %>"
<% end %>
>
<%= radio_button_tag(@option_id, option.value, nil, { id: @option_id, name: question.ui_selector, class: "usa-radio__input usa-radio__input--tile", required: question.is_required }) %>
<%= label_tag(@option_id, nil, class: "usa-radio__label") do %><%= option.text %><% end %>
<%= radio_button_tag(question.ui_selector, option[:value], nil, {
id: @option_id,
class: "usa-radio__input usa-radio__input--tile",
required: question.is_required
}) %>
<%= label_tag(@option_id, option.text, class: "usa-radio__label") %>
<%- if option.other_option %>
<div class="margin-top-1">
<div
class="margin-top-1">
<%= label_tag(nil, for: "#{question.ui_selector}_other", class: "usa-input__label") do %><%= t 'form.enter_other_text' %><% end %>
<input type="text"
name="<%= question.ui_selector %>_other"
Expand Down
2 changes: 1 addition & 1 deletion app/views/components/widget/_fba.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ var touchpointFormOptions<%= form.short_uuid %> = {
'css' : "<%= escape_javascript(render partial: 'components/widget/widget', formats: :css, locals: { form: form }) %>",
'loadCSS' : <%= form.load_css %>,
'formSpecificScript' : function() {
<%- if ["a11_v2", "a11_yes_no"].include?(form.kind) %>
<%- if ["a11_v2", "a11_v2_radio", "a11_yes_no"].include?(form.kind) %>
<%= render "components/form_#{form.kind}_script", form: form %>
<% end %>
},
Expand Down
Loading