From 3736b7bac07f161ee0a44183bcde2c601a8067bf Mon Sep 17 00:00:00 2001 From: Samuel Culley Date: Thu, 27 Aug 2026 17:08:27 +0100 Subject: [PATCH] WIP shows routes with exit pages This currently shows routes on the live pages view in all cases, for goto pages, skip to end and exit pages. There's still a chunk left to do, as the exit page contents needs to be displayed at the end of each page section, and the Welsh translations variant of the page list view needs this behaviour as well. I started refactoring the logic that constructs the answer_value_groups but didn't quite get far enough. At the moment, that method is very clunky, and should probably be broken up into multiple methods. --- app/models/form_document/exit_page.rb | 16 +++++++ app/models/form_document/step.rb | 3 +- app/services/step_summary_card_service.rb | 58 +++++++++++++++++++---- config/locales/en.yml | 1 + 4 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 app/models/form_document/exit_page.rb diff --git a/app/models/form_document/exit_page.rb b/app/models/form_document/exit_page.rb new file mode 100644 index 0000000000..7628bcde74 --- /dev/null +++ b/app/models/form_document/exit_page.rb @@ -0,0 +1,16 @@ +class FormDocument::ExitPage + include ActiveModel::API + include ActiveModel::Attributes + + attribute :id, :integer + attribute :created_at, :datetime + attribute :updated_at, :datetime + attribute :question_page_id, :string + attribute :heading, :string + attribute :markdown, :string + + def initialize(attributes = {}) + attributes.slice!(*self.class.attribute_names) + super + end +end diff --git a/app/models/form_document/step.rb b/app/models/form_document/step.rb index 5bdc6fe53c..cceca4351a 100644 --- a/app/models/form_document/step.rb +++ b/app/models/form_document/step.rb @@ -2,7 +2,7 @@ class FormDocument::Step include ActiveModel::API include ActiveModel::Attributes - attr_reader :routing_conditions + attr_reader :routing_conditions, :exit_pages attribute :id, :string attribute :data, DataStructType.new @@ -14,6 +14,7 @@ class FormDocument::Step def initialize(attributes = {}) @routing_conditions = attributes.fetch("routing_conditions", []).map { |condition| FormDocument::Condition.new(**condition) } + @exit_pages = attributes.fetch("exit_pages", []).map { |exit_page| FormDocument::ExitPage.new(**exit_page) } attributes.slice!(*self.class.attribute_names) super end diff --git a/app/services/step_summary_card_service.rb b/app/services/step_summary_card_service.rb index 4cc9a1ed51..5d4daf0732 100644 --- a/app/services/step_summary_card_service.rb +++ b/app/services/step_summary_card_service.rb @@ -225,9 +225,13 @@ def print_unconditional_route(condition) def print_routes(conditions) answer_value_groups = answer_value_groups(conditions) - answer_value_groups.map { |goto_page_id, condition_group| - if goto_page_id.nil? + answer_value_groups.map { |group| + condition_group = group[:conditions] + + if group[:group_type] == :skip_to_end caption = content_tag(:p, I18n.t("page_conditions.go_to_the_end"), class: "govuk-body-s") + elsif group[:group_type] == :exit_page + caption = content_tag(:p, I18n.t("page_conditions.go_to_exit_page", exit_page_index: group[:exit_page_index], exit_page_heading: group[:exit_page].heading), class: "govuk-body-s") else goto_question = @steps.find { |page| page.id == condition_group.first.goto_page_id } goto_page_question_text = ActionController::Base.helpers.sanitize(goto_question.question_text) @@ -288,12 +292,50 @@ def html_list_item(item) end def answer_value_groups(conditions) - answer_order = @step.answer_settings.selection_options.map(&:value) || [] + answer_order = @step.answer_settings&.selection_options&.map(&:value) || [] + + ordered_conditions = conditions.to_a + .in_order_of(:answer_value, answer_order, filter: false) + + groups = [] + + goto_page_groups = ordered_conditions.select { |condition| condition.goto_page_id.present? }.group_by(&:goto_page_id) + goto_page_groups.each_value do |grouped_conditions| + groups << { + group_type: :goto_page, + conditions: grouped_conditions, + } + end + + skip_to_end_conditions = ordered_conditions.select(&:skip_to_end) + + if skip_to_end_conditions.any? + groups << { + group_type: :skip_to_end, + conditions: skip_to_end_conditions, + } + end + + exit_page_groups = ordered_conditions.select { |condition| condition.exit_page_id.present? } + .group_by(&:exit_page_id) + .values + .sort_by { |grouped_conditions| grouped_conditions.first.exit_page_id } + + exit_page_groups.each do |grouped_conditions| + exit_page = @step.exit_pages.detect { it.id == grouped_conditions.first.exit_page_id } + + groups << { + group_type: :exit_page, + exit_page_index: exit_page_position_calc(exit_page), + conditions: grouped_conditions, + exit_page:, + } + end + + groups + end - conditions.group_by(&:goto_page_id).map { |goto_page_id, condition_group| - goto_page_position = @steps.find_index { |page| page.id == goto_page_id } + 1 unless goto_page_id.nil? - sorted_condition_group = condition_group.in_order_of(:answer_value, answer_order, filter: false) - [goto_page_position, sorted_condition_group] - }.sort_by { |goto_page_position, _| goto_page_position || Float::INFINITY } + def exit_page_position_calc(exit_page) + @step.exit_pages.find_index(exit_page) + 1 end end diff --git a/config/locales/en.yml b/config/locales/en.yml index f7fb145373..6a1983b235 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1686,6 +1686,7 @@ en: exit_page_label: An ‘exit page’ to leave the form go_to_page: 'Go to %{goto_page_question_number}, ‘%{goto_page_question_text}’ if the answer is:' go_to_the_end: 'Go to the end of the form if the answer is:' + go_to_exit_page: 'Go to exit page %{exit_page_index}, ‘%{exit_page_heading}’ if the answer is:' none_of_the_above: None of the above route: Route route2: