diff --git a/app/components/check_answers_summary_list_card_component.html.erb b/app/components/check_answers_summary_list_card_component.html.erb index 4a26b8c8d..4c1f9aa2d 100644 --- a/app/components/check_answers_summary_list_card_component.html.erb +++ b/app/components/check_answers_summary_list_card_component.html.erb @@ -35,8 +35,8 @@ <% if @log.collection_period_open_for_editing? %> <% row.with_action( - text: question.action_text(log), - href: action_href(question, log), + text: question.action_text(log, correcting_hard_validation: @correcting_hard_validation), + href: correct_validation_action_href(question, log, applicable_questions.map(&:id), @correcting_hard_validation), visually_hidden_text: question.check_answer_label.to_s.downcase, ) %> <% end %> diff --git a/app/components/check_answers_summary_list_card_component.rb b/app/components/check_answers_summary_list_card_component.rb index 205a8516e..5242c7f41 100644 --- a/app/components/check_answers_summary_list_card_component.rb +++ b/app/components/check_answers_summary_list_card_component.rb @@ -1,10 +1,11 @@ class CheckAnswersSummaryListCardComponent < ViewComponent::Base attr_reader :questions, :log, :user - def initialize(questions:, log:, user:) + def initialize(questions:, log:, user:, correcting_hard_validation: false) @questions = questions @log = log @user = user + @correcting_hard_validation = correcting_hard_validation super end @@ -33,6 +34,16 @@ class CheckAnswersSummaryListCardComponent < ViewComponent::Base send("#{log.model_name.param_key}_#{question.page.id}_path", log, referrer:) end + def correct_validation_action_href(question, log, _related_question_ids, correcting_hard_validation) + return action_href(question, log) unless correcting_hard_validation + + if question.displayed_as_answered?(log) + send("#{log.model_name.param_key}_confirm_clear_answer_path", log, question_id: question.id) + else + send("#{log.model_name.param_key}_#{question.page.id}_path", log, referrer: "check_errors", related_question_ids: request.query_parameters["related_question_ids"], original_page_id: request.query_parameters["original_page_id"]) + end + end + private def unanswered_value(question) diff --git a/app/controllers/check_errors_controller.rb b/app/controllers/check_errors_controller.rb new file mode 100644 index 000000000..f246e0b01 --- /dev/null +++ b/app/controllers/check_errors_controller.rb @@ -0,0 +1,37 @@ +class CheckErrorsController < ApplicationController + include DuplicateLogsHelper + + before_action :authenticate_user! + before_action :find_resource_by_named_id + + def confirm_clear_answer + return render_not_found unless @log + + @related_question_ids = params[@log.model_name.param_key].keys.reject { |id| id == "page_id" } + @page = @log.form.get_page(params[@log.model_name.param_key]["page_id"]) + + if params["clear_all"] + @questions_to_clear = @related_question_ids.map { |id| + question = @log.form.get_question(id, @log) + next if question.subsection.id == "setup" + + question.page.questions.map(&:id) + }.flatten.compact + + render :confirm_clear_all_answers + else + question_id = @related_question_ids.find { |id| !params[id].nil? } + @question = @log.form.get_question(question_id, @log) + end + end + +private + + def find_resource_by_named_id + @log = if params[:sales_log_id].present? + current_user.sales_logs.visible.find_by(id: params[:sales_log_id]) + else + current_user.lettings_logs.visible.find_by(id: params[:lettings_log_id]) + end + end +end diff --git a/app/controllers/form_controller.rb b/app/controllers/form_controller.rb index a8d8fca48..d84f8642a 100644 --- a/app/controllers/form_controller.rb +++ b/app/controllers/form_controller.rb @@ -9,6 +9,8 @@ class FormController < ApplicationController def submit_form if @log @page = form.get_page(params[@log.model_name.param_key][:page]) + return render_check_errors_page if params["check_errors"] + shown_page_ids_with_unanswered_questions_before_update = @page.subsection.pages .select { |page| page.routed_to?(@log, current_user) } .select { |page| page.has_unanswered_questions?(@log) } @@ -30,7 +32,8 @@ class FormController < ApplicationController mandatory_questions_with_no_response.map do |question| @log.errors.add question.id.to_sym, question.unanswered_error_message, category: :not_answered end - Rails.logger.info "User triggered validation(s) on: #{@log.errors.map(&:attribute).join(', ')}" + error_attributes = @log.errors.map(&:attribute) + Rails.logger.info "User triggered validation(s) on: #{error_attributes.join(', ')}" @subsection = form.subsection_for_page(@page) restore_error_field_values(@page&.questions) render "form/page" @@ -64,12 +67,23 @@ class FormController < ApplicationController @interruption_page_referrer_type = from_referrer_query("referrer") end + if adding_answer_from_check_errors_page? + @related_question_ids = request.params["related_question_ids"] + @original_page_id = request.params["original_page_id"] + @check_errors = true + end + if @log page_id = request.path.split("/")[-1].underscore @page = form.get_page(page_id) @subsection = form.subsection_for_page(@page) - if @page.routed_to?(@log, current_user) || is_referrer_type?("interruption_screen") - render "form/page" + if @page.routed_to?(@log, current_user) || is_referrer_type?("interruption_screen") || adding_answer_from_check_errors_page? + if updated_answer_from_check_errors_page? + @questions = request.params["related_question_ids"].map { |id| @log.form.get_question(id, @log) } + render "form/check_errors" + else + render "form/page" + end else redirect_to @log.lettings? ? lettings_log_path(@log) : sales_log_path(@log) end @@ -213,6 +227,20 @@ private return send("#{@log.class.name.underscore}_#{previous_interruption_screen_page_id}_path", @log, { referrer: previous_interruption_screen_referrer, original_log_id: original_duplicate_log_id_from_query }.compact) end + if params[@log.model_name.param_key]["check_errors"] + @page = form.get_page(params[@log.model_name.param_key]["page"]) + flash[:notice] = "You have successfully updated #{@page.questions.map(&:check_answer_label).to_sentence}" + original_page_id = params[@log.model_name.param_key]["original_page_id"] + related_question_ids = params[@log.model_name.param_key]["related_question_ids"].split(" ") + return send("#{@log.class.name.underscore}_#{original_page_id}_path", @log, { check_errors: true, related_question_ids: }.compact) + end + + if params["referrer"] == "check_errors" + @page = form.get_page(params[@log.model_name.param_key]["page"]) + flash[:notice] = "You have successfully updated #{@page.questions.map(&:check_answer_label).to_sentence}" + return send("#{@log.class.name.underscore}_#{params['original_page_id']}_path", @log, { check_errors: true, related_question_ids: params["related_question_ids"] }.compact) + end + is_new_answer_from_check_answers = is_referrer_type?("check_answers_new_answer") redirect_path = form.next_page_redirect_path(@page, @log, current_user, ignore_answered: is_new_answer_from_check_answers) referrer = is_new_answer_from_check_answers ? "check_answers_new_answer" : nil @@ -374,4 +402,34 @@ private true end + + def render_check_errors_page + if params[@log.model_name.param_key]["clear_question_ids"].present? + question_ids = params[@log.model_name.param_key]["clear_question_ids"].split(" ") + question_ids.each do |question_id| + question = @log.form.get_question(question_id, @log) + next if question.subsection.id == "setup" + + question.page.questions.map(&:id).each { |id| @log[id] = nil } + end + @log.save! + @questions = params[@log.model_name.param_key].keys.reject { |id| %w[clear_question_ids page].include?(id) }.map { |id| @log.form.get_question(id, @log) } + else + responses_for_page = responses_for_page(@page) + @log.assign_attributes(responses_for_page) + @log.valid? + @log.reload + error_attributes = @log.errors.map(&:attribute) + @questions = @log.form.questions.select { |q| error_attributes.include?(q.id.to_sym) } + end + render "form/check_errors" + end + + def adding_answer_from_check_errors_page? + request.params["referrer"] == "check_errors" + end + + def updated_answer_from_check_errors_page? + params["check_errors"] + end end diff --git a/app/frontend/styles/_button.scss b/app/frontend/styles/_button.scss index 5975da0cb..4cd815b5b 100644 --- a/app/frontend/styles/_button.scss +++ b/app/frontend/styles/_button.scss @@ -29,3 +29,11 @@ $app-button-inverse-hover-background-colour: govuk-tint($app-button-inverse-fore background-color: $app-button-inverse-hover-background-colour; box-shadow: inset 0 0 0 2px $govuk-focus-colour; } + +.submit-button-link { + background: none; + border: none; + color: #1d70b8; + text-decoration: underline; + cursor: pointer; +} diff --git a/app/helpers/check_errors_helper.rb b/app/helpers/check_errors_helper.rb new file mode 100644 index 000000000..6d1ff0166 --- /dev/null +++ b/app/helpers/check_errors_helper.rb @@ -0,0 +1,11 @@ +module CheckErrorsHelper + include GovukLinkHelper + + def check_errors_answer_text(question, log) + question.displayed_as_answered?(log) ? "Change" : "Answer" + end + + def check_errors_answer_link(log, question, page, applicable_questions) + send("#{log.model_name.param_key}_#{question.page.id}_path", log, referrer: "check_errors", original_page_id: page.id, related_question_ids: applicable_questions.map(&:id)) + end +end diff --git a/app/helpers/form_page_error_helper.rb b/app/helpers/form_page_error_helper.rb index 4bfda9eee..8a46accca 100644 --- a/app/helpers/form_page_error_helper.rb +++ b/app/helpers/form_page_error_helper.rb @@ -3,4 +3,8 @@ module FormPageErrorHelper other_page_error_ids = lettings_log.errors.map(&:attribute) - page.questions.map { |q| q.id.to_sym }.concat([:base]) other_page_error_ids.each { |id| lettings_log.errors.delete(id) } end + + def all_questions_affected_by_errors(log) + log.errors.map(&:attribute) - [:base] + end end diff --git a/app/models/form/question.rb b/app/models/form/question.rb index a692574dd..960af8909 100644 --- a/app/models/form/question.rb +++ b/app/models/form/question.rb @@ -111,8 +111,10 @@ class Form::Question end end - def action_text(log) - displayed_as_answered?(log) ? "Change" : "Answer" + def action_text(log, correcting_hard_validation: false) + return "Answer" unless displayed_as_answered?(log) + + correcting_hard_validation ? "Clear" : "Change" end def displayed_as_answered?(log) diff --git a/app/views/check_errors/confirm_clear_all_answers.html.erb b/app/views/check_errors/confirm_clear_all_answers.html.erb new file mode 100644 index 000000000..85e936aef --- /dev/null +++ b/app/views/check_errors/confirm_clear_all_answers.html.erb @@ -0,0 +1,32 @@ +<% content_for :before_content do %> + <% content_for :title, "Are you sure you want to clear all?" %> +<% end %> + +
You've selected <%= @questions_to_clear.count %> answers to clear
+ + <%= govuk_warning_text(text: "Dependent answers related to this question may also get cleared. You will not be able to undo this action") %> + <%= form_with model: @log, url: send("#{@log.model_name.param_key}_#{@page.id}_path", @log), method: "post", local: true do |f| %> + + <% @related_question_ids.each do |id| %> + <%= f.hidden_field id, value: @log[id] %> + <% end %> + + <%= f.hidden_field :clear_question_ids, value: @questions_to_clear %> + <%= f.hidden_field :page, value: @page.id %> + + + <% end %> +