diff --git a/app/assets/javascripts/frontend/custom_questions/support_letters.js.coffee b/app/assets/javascripts/frontend/custom_questions/support_letters.js.coffee index 45e28c79f..af3e491b8 100644 --- a/app/assets/javascripts/frontend/custom_questions/support_letters.js.coffee +++ b/app/assets/javascripts/frontend/custom_questions/support_letters.js.coffee @@ -2,17 +2,18 @@ window.SupportLetters = init: -> $('.js-support-letter-attachment').each (idx, el) -> SupportLetters.fileupload_init(el) - SupportLetters.save_collection_init() + + $(document).on 'change', '.js-trigger-autosave', debounce(SupportLetters.submit, 1000) new_item_init: (el) -> SupportLetters.clean_up_system_tags(el) SupportLetters.enable_item_fields_and_controls(el) - SupportLetters.fileupload_init(el.find(".js-support-letter-attachment")) + SupportLetters.fileupload_init(el.find('.js-support-letter-attachment')) el.find('input,textarea,select').first().focus() fileupload_init: (el) -> $el = $(el) - parent = $el.closest(".govuk-form-group") + parent = $el.closest('.govuk-form-group') upload_done = (e, data) -> SupportLetters.clean_up_system_tags(parent) @@ -20,20 +21,23 @@ window.SupportLetters = if data.result['original_filename'] filename = data.result['original_filename'] else - filename = "File uploaded" - file_title = $("
") - hidden_input = $("") - - parent.find(".govuk-error-message").html("") - parent.find(".govuk-error-message").closest(".govuk-form-group").removeClass("govuk-form-group--error") - parent.append(file_title) - parent.append(hidden_input) + filename = 'File uploaded' + + parent.find('.govuk-error-message').html('') + parent.find('.govuk-error-message').closest('.govuk-form-group').removeClass('govuk-form-group--error') + + label = $(' ') + hiddenInput = $("") + + parent.append(label) + parent.append(hiddenInput) SupportLetters.autosave() + SupportLetters.submit(e) failed = (error_message) -> SupportLetters.clean_up_system_tags(parent) - parent.find(".govuk-error-message").html(error_message) - parent.closest(".govuk-form-group").addClass("govuk-form-group--error") + parent.find('.govuk-error-message').html(error_message) + parent.closest('.govuk-form-group').addClass('govuk-form-group--error') success_or_error = (e, data) -> errors = data.result.errors @@ -44,108 +48,30 @@ window.SupportLetters = upload_done(e, data) $el.fileupload( - url: $el.closest(".list-add").data('attachments-url') + ".json" + url: $el.closest('.list-add').data('attachments-url') + '.json' forceIframeTransport: true dataType: 'json' formData: [ - { name: "authenticity_token", value: $("meta[name='csrf-token']").attr("content") } + { name: 'authenticity_token', value: $('meta[name="csrf-token"]').attr('content') } ] always: success_or_error ) clean_up_system_tags: (parent) -> - parent.find("input[type='hidden']").remove() - parent.find(".support-letter-attachment-filename").remove() + parent.find('input[type="hidden"]').remove() + parent.find('.support-letter-attachment-filename').remove() enable_item_fields_and_controls: (parent) -> - parent.find(".js-save-collection").removeClass("govuk-!-display-none") - parent.find(".visible-read-only").hide() - fields = parent.find("input") - fields.removeClass("read-only") - parent.find(".govuk-error-message").html("") - form_name_prefix = parent.find(".js-system-tag").data("new-hidden-input-name") - letter_id_hidden_input = $("").prop('type', 'hidden'). - prop('name', form_name_prefix) - parent.append(letter_id_hidden_input) - - disable_item_fields_and_controls: (parent) -> - parent.find(".js-save-collection").addClass("govuk-!-display-none") - parent.find(".visible-read-only").show() - fields = parent.find("input") - fields.addClass("read-only") - - save_collection_init: () -> - $(document).on 'click', '.js-save-collection', (e) -> - e.preventDefault() - e.stopPropagation() - - button = $(this) - parent = $(this).closest("li") - - if !button.hasClass("govuk-!-display-none") - save_url = button.data 'save-collection-url' - - first_name = parent.find(".js-support-letter-first-name").val() - last_name = parent.find(".js-support-letter-last-name").val() - email = parent.find(".js-support-letter-email").val() - relationship_to_nominee = parent.find(".js-support-letter-relationship-to-nominee").val() - attachment_id = parent.find(".js-support-letter-attachment-id").val() - - data = { - "support_letter": { - "first_name": first_name, - "last_name": last_name, - "relationship_to_nominee": relationship_to_nominee - } - } - - if attachment_id - data["support_letter"]["attachment"] = attachment_id - - if email - data["support_letter"]["email"] = email - - if save_url - $.ajax - url: save_url - type: 'post' - data: data - dataType: 'json' - success: (response) -> - parent.find(".js-support-entry-id").prop('value', response) - parent.find(".govuk-error-message").html("") - parent.removeClass("govuk-form-group--error") - parent.addClass("read-only") - parent.addClass("js-support-letter-received") - parent.closest('li').find("input[type='text']").each -> - show_el = $(this).closest(".govuk-form-group").find(".visible-read-only") - show_el.text($(this).val()) - SupportLetters.disable_item_fields_and_controls(parent) - window.FormValidation.validateStep() - SupportLetters.autosave() - SupportLetters.showRemoveLink(parent, data, response) - - return - error: (response) -> - parent.find(".govuk-error-message").html("") - parent.removeClass("govuk-form-group--error") - error_message = response.responseText - $.each $.parseJSON(response.responseText), (question_key, error_message) -> - key_selector = ".js-support-letter-" + question_key.replace(/_/g, "-") - field_error_container = parent.find(key_selector). - closest(".govuk-form-group"). - find(".govuk-error-message") - field_error_container.html(error_message[0]) - field_error_container.closest(".govuk-form-group").addClass("govuk-form-group--error") - button.removeClass("govuk-visually-hidden") - - return + parent.find('.govuk-error-message').html('') + prefixed = parent.find('.js-system-tag').data('new-hidden-input-name') + hiddenInput = $('').prop('type', 'hidden').prop('name', prefixed) + parent.append(hiddenInput) autosave: () -> url = $('form.qae-form').data('autosave-url') if url # Setting current_step_id to form as we updating only current section form_data (not whole form) - $("#current_step_id").val($(".js-step-condition.step-current").attr("data-step")) + $('#current_step_id').val($('.js-step-condition.step-current').attr('data-step')) form_data = $('form.qae-form').serialize() $.ajax({ @@ -155,8 +81,71 @@ window.SupportLetters = dataType: 'json' }) - showRemoveLink: (parent, data, response) -> - removeLink = $(".remove-supporter", parent) - removeLink.data("url", "/users/form_answers/#{response['form_answer_id']}/support_letters/#{response['id']}") - removeLink.attr("aria-label", "Delete support letter from #{data['support_letter']['first_name']} #{data['support_letter']['last_name']}") - removeLink.removeClass("govuk-!-display-none") + submit: (e) -> + e.preventDefault() + e.stopPropagation() + + target = $(e.target) + parent = target.closest("li") + + data = {'support_letter': {}} + data['support_letter']['first_name'] = parent.find('.js-support-letter-first-name').val() + data['support_letter']['last_name'] = parent.find('.js-support-letter-last-name').val() + data['support_letter']['relationship_to_nominee'] = parent.find('.js-support-letter-relationship-to-nominee').val() + + attachmentId = parent.find('.js-support-letter-attachment-id').val() + if attachmentId + data['support_letter']['attachment'] = attachmentId + + email = parent.find('.js-support-letter-email').val() + if email + data['support_letter']['email'] = email + + createUrl = parent.data('create-url') + updateUrl = parent.data('update-url') + persistUrl = updateUrl || createUrl + + type = if !!updateUrl + 'put' + else + 'post' + + if persistUrl + $.ajax + url: persistUrl + type: type + data: data + dataType: 'json' + success: (response) -> + parent.find('.js-support-entry-id').prop('value', response['id']) + parent.find('.govuk-error-message').html('') + parent.removeClass('govuk-form-group--error') + parent.addClass('js-support-letter-received') + parent.attr('data-update-url', response['update_url']) + window.FormValidation.validateStep() + SupportLetters.autosave() + + return + error: (response) -> + parent.find('.govuk-error-message').html('') + parent.removeClass('govuk-form-group--error') + msg = response.responseText + $.each $.parseJSON(response.responseText), (key, msg) -> + selector = '.js-support-letter-' + key.replace(/_/g, '-') + + errorContainer = parent.find(selector).closest('.govuk-form-group').find('.govuk-error-message') + errorContainer.html(msg[0]) + errorContainer.closest('.govuk-form-group').addClass('govuk-form-group--error') + + return + +debounce = (fn, wait = 500) -> + last = (new Date) - wait + -> + now = new Date + + # Return if we haven't waited long enough + return if wait > (now - last) + + fn.apply null, arguments + last = now \ No newline at end of file diff --git a/app/controllers/form/support_letters_controller.rb b/app/controllers/form/support_letters_controller.rb index cd0a41211..fa581277a 100644 --- a/app/controllers/form/support_letters_controller.rb +++ b/app/controllers/form/support_letters_controller.rb @@ -1,100 +1,59 @@ class Form::SupportLettersController < Form::BaseController - before_action :load_letter, only: :destroy + include FormAnswerSubmissionMixin def create - @support_letter = @form_answer.support_letters.new( - support_letter_params.merge( - user_id: current_user.id, - manual: true - ) - ) - - attachment = SupportLetterAttachment.new(attachment_params) - attachment.user = current_user - attachment.form_answer = @form_answer - attachment.original_filename = attachment_params[:attachment].try(:original_filename) - @support_letter.support_letter_attachment = attachment - - if @support_letter.save - add_support_letter_to_document! - @form_answer.save - - redirect_to form_form_answer_supporters_path(@form_answer) + @form_answer.support_letters_attributes = permitted_params["support_letters_attributes"] + @form_answer.document = prepare_doc if params[:form].present? + + if @form_answer.valid? && @form_answer.save + add_support_letters_to_document! + + if params[:next_step_id] + redirect_to edit_form_url(@form_answer, step: params[:next_step_id]) + else + redirect_to form_form_answer_supporters_path(@form_answer) + end else - render :new - end - end + @step = @form.steps.detect { |s| s.opts[:id] == :letters_of_support_step } - def new - @support_letter = @form_answer.support_letters.new - end - - def destroy - # safeguard for the case when not a user tries to delete a letter - return if current_assessor || current_lieutenant - - if @support_letter.destroy - remove_support_letter_from_document! - @form_answer.save + render "form/supporters/index" end - - redirect_to form_form_answer_supporters_path(@form_answer) end private - def support_letter_params - params[:support_letter].permit( - :first_name, - :last_name, - :relationship_to_nominee + def permitted_params + params.require(:form_answer).permit( + support_letters_attributes: [ + :id, + :first_name, + :last_name, + :relationship_to_nominee, + :user_id, + :manual, + support_letter_attachment_attributes: [ + :id, + :attachment, + :attachment_cache, + :form_answer_id, + :user_id + ] + ] ) end - def attachment_params - if params[:support_letter] && params[:support_letter][:support_letter_attachment] - params[:support_letter][:support_letter_attachment].permit(:attachment) - else - {} - end - end - - def load_letter - @support_letter = @form_answer.support_letters.find(params[:id]) - end - - def add_support_letter_to_document! - letters = support_letters_doc - - new_letter = { - support_letter_id: @support_letter.id, - first_name: @support_letter.first_name, - last_name: @support_letter.last_name, - relationship_to_nominee: @support_letter.relationship_to_nominee, - letter_of_support: @support_letter.support_letter_attachment.id - } - - letters << new_letter - - @form_answer.document = @form_answer.document.merge(supporter_letters_list: letters, - manually_upload: "yes") - end - - def remove_support_letter_from_document! - letters = support_letters_doc - - letters.delete_if do |sup| - sup["support_letter_id"] == @support_letter.id + def add_support_letters_to_document! + list = @form_answer.support_letters.each_with_object([]) do |support_letter, memo| + memo << Hash[].tap do |h| + h[:support_letter_id] = support_letter.id + h[:first_name] = support_letter.first_name + h[:last_name] = support_letter.last_name + h[:relationship_to_nominee] = support_letter.relationship_to_nominee + h[:letter_of_support] = support_letter.support_letter_attachment.id + end end - @form_answer.document = @form_answer.document.merge(supporter_letters_list: letters) - end - - def support_letters_doc - if @form_answer.document["supporter_letters_list"].present? - @form_answer.document["supporter_letters_list"] - else - [] - end + @form_answer.document = @form_answer.document.merge(supporter_letters_list: list, manually_upload: "yes") + @form_answer.save! end end diff --git a/app/controllers/form_controller.rb b/app/controllers/form_controller.rb index 2316934c9..d9f16781f 100644 --- a/app/controllers/form_controller.rb +++ b/app/controllers/form_controller.rb @@ -115,11 +115,8 @@ def save redirect_to edit_form_url(@form_answer, step: params[:next_step]) else params[:step] = @form_answer.steps_with_errors.try(:first) - # avoid redirecting to supporters page - if !params[:step] || params[:step] == "letters-of-support" - params[:step] = @form.steps.first.title_to_param - end - + params[:step] ||= @form.steps.first.title_to_param + render template: "qae_form/show" end end diff --git a/app/controllers/users/support_letters_controller.rb b/app/controllers/users/support_letters_controller.rb index 940bb16c1..2421e939f 100644 --- a/app/controllers/users/support_letters_controller.rb +++ b/app/controllers/users/support_letters_controller.rb @@ -12,7 +12,7 @@ class Users::SupportLettersController < Users::BaseController expose(:support_letter) do form_answer.support_letters.new( support_letter_params.merge({ - user_id: current_user.try(:id) || form_answer.user_id, + user_id: current_user&.id || form_answer.user_id, manual: true, support_letter_attachment: attachment }) @@ -30,11 +30,35 @@ def create attachment.support_letter = support_letter attachment.save! - render json: { id: support_letter.id, form_answer_id: form_answer.id }, - status: :created + render json: { + id: support_letter.id, + form_answer_id: form_answer.id, + update_url: users_form_answer_support_letter_path(form_answer, support_letter) + }, status: :created else - render json: support_letter.errors.messages.to_json, - status: :unprocessable_entity + render json: support_letter.errors.messages.to_json, status: :unprocessable_entity + end + end + + def update + @support_letter = form_answer.support_letters.find(params[:id]) + + if @support_letter.update(support_letter_params) + attachment.support_letter = @support_letter + attachment.save! + + SupportLetterAttachment + .where(support_letter: @support_letter) + .where.not(id: attachment.id) + .destroy_all + + render json: { + id: @support_letter.id, + form_answer_id: form_answer.id, + update_url: users_form_answer_support_letter_path(form_answer, @support_letter) + }, status: :ok + else + render json: @support_letter.errors.messages.to_json, status: :unprocessable_entity end end diff --git a/app/javascript/packs/application.scss b/app/javascript/packs/application.scss index e8dbc4ba2..aef597acd 100644 --- a/app/javascript/packs/application.scss +++ b/app/javascript/packs/application.scss @@ -105,6 +105,10 @@ body.js-enabled { margin-top: 0 !important; white-space: nowrap; } + + a.govuk-button { + color: inherit; + } } .previous { diff --git a/app/models/form_answer.rb b/app/models/form_answer.rb index 4f8a80ca5..c5b9d2adc 100644 --- a/app/models/form_answer.rb +++ b/app/models/form_answer.rb @@ -124,6 +124,8 @@ class FormAnswer < ApplicationRecord before_create :set_user_info end + accepts_nested_attributes_for :support_letters, reject_if: :dismiss_support_letters + store_accessor :document store_accessor :financial_data @@ -137,7 +139,6 @@ def state_machine end end - # FormAnswer#award_form # fetches relevant award form for the application's award year if available # else uses form for the current award year @@ -436,6 +437,10 @@ def award_form_class_name(year) "::AwardYears::V#{year}::QaeForms" end + def dismiss_support_letters(attributes) + %w(first_name last_name relationship_to_nominee).all? { |attr| attributes[attr].blank? } + end + def self.transition_class FormAnswerTransition end diff --git a/app/models/support_letter.rb b/app/models/support_letter.rb index a98559472..b018e75a1 100644 --- a/app/models/support_letter.rb +++ b/app/models/support_letter.rb @@ -22,6 +22,8 @@ class SupportLetter < ApplicationRecord scope :not_manual, -> { where(manual: false) } end + accepts_nested_attributes_for :support_letter_attachment + attr_accessor :attachment def full_name diff --git a/app/models/support_letter_attachment.rb b/app/models/support_letter_attachment.rb index 7ba459d4e..0ceb2e102 100644 --- a/app/models/support_letter_attachment.rb +++ b/app/models/support_letter_attachment.rb @@ -19,4 +19,14 @@ class SupportLetterAttachment < ApplicationRecord maximum: 5.megabytes.to_i } end + + begin :callbacks + before_save :assign_original_filename, if: :will_save_change_to_attachment? + end + + private + + def assign_original_filename + self.original_filename = self&.attachment&.identifier + end end diff --git a/app/views/assessor/form_answers/questions/_supporters_question.html.slim b/app/views/assessor/form_answers/questions/_supporters_question.html.slim index d3d4f472e..916785e16 100644 --- a/app/views/assessor/form_answers/questions/_supporters_question.html.slim +++ b/app/views/assessor/form_answers/questions/_supporters_question.html.slim @@ -1,16 +1,4 @@ input name="form[#{question.key}][array]" value="true" type="hidden" disabled="disabled" ul.list-add.supporters-list data-need-to-clear-example=true data-add-limit=question.limit data-attachments-url=(users_form_answer_support_letter_attachments_path(@form_answer)) data-example-has-file-field=true - = render 'qae_form/supporter_fields_placeholder', question: question - - if question.entities.present? - - if question.entities.count < question.default.to_i - - question.entities.each_with_index do |supporter, index| - = render 'qae_form/supporter_fields', question: question, supporter: supporter, index: index - - else - - question.entities.each_with_index do |supporter, index| - = render 'qae_form/supporter_fields', question: question, supporter: supporter, index: index - - else - - (0...question.default.to_i).each do |index| - = render 'qae_form/supporter_fields', question: question, supporter: {}, index: index - -a.govuk-button.govuk-button--secondary.button-add.js-button-add href="#" disabled="disabled" - | Add another letter of support + - question.entities.each_with_index do |supporter, index| + = render 'qae_form/supporter_fields', question: question, supporter: supporter, index: index diff --git a/app/views/form/support_letters/_footer.html.slim b/app/views/form/support_letters/_footer.html.slim new file mode 100644 index 000000000..bfb5da726 --- /dev/null +++ b/app/views/form/support_letters/_footer.html.slim @@ -0,0 +1,21 @@ +nav.pagination.no-border class="#{'pagination-alternative' unless step.next}" role="navigation" aria-label="Pagination" + ul.group + - if step.previous + li.previous.previous-alternate.js-step-link data-step="step-#{step.previous.title_to_param}" + = link_to edit_form_url(id: @form_answer.id, step: step.previous.title_to_param), rel: "prev", title: "Navigate to previous part", class: 'govuk-button govuk-button--secondary' do + span.pagination-label + | Back + + - else + li.previous.previous-alternate + = link_to [:award_info, @form_answer.award_type.to_sym, form_id: @form_answer.id], rel: "prev", title: "Navigate to previous part", class: 'govuk-button govuk-button--secondary' do + span.pagination-label + | Back + + - unless admin_in_read_only_mode? + li.save-quit-link + = link_to "Save and come back later", dashboard_path, class: "save-quit-link govuk-button govuk-button--secondary" + + - if step.next + li.submit.js-next-link.js-step-link data-step="step-#{step.next.title_to_param}" + = f.submit "Save and continue", class: "govuk-button", title: "Submit letters of support" diff --git a/app/views/form/support_letters/_form.html.slim b/app/views/form/support_letters/_form.html.slim new file mode 100644 index 000000000..6e0f6eae1 --- /dev/null +++ b/app/views/form/support_letters/_form.html.slim @@ -0,0 +1,25 @@ += f.simple_fields_for :support_letters do |ff| + - idx = ff.options[:child_index] + 1 + li + .govuk-grid-row + .govuk-grid-column-one-half + label[class="govuk-label"] + span[class="govuk-body govuk-!-font-size-20 govuk-!-font-weight-bold govuk-!-display-block"] + = "Letter of Support #{idx}" + = ff.input :first_name, label: "First Name:", input_html: { class: "form-control" } + = ff.input :last_name, label: "Surname:", input_html: { class: "form-control" } + = ff.input :relationship_to_nominee, label: "Relationship to Group:", input_html: { class: "form-control" } + + = ff.input :manual, as: :hidden, input_html: { value: true } + = ff.input :user_id, as: :hidden, input_html: { value: current_user.id } + + = ff.simple_fields_for :support_letter_attachment, (ff.object.support_letter_attachment || ff.object.build_support_letter_attachment) do |fff| + = fff.input :attachment, as: :file, label: "Upload Letter of Support #{idx}", input_html: { class: "form-control" }, wrapper_html: { style: "margin-bottom: -1rem;" } + p.govuk-body.support-letter-attachment-filename + = render "shared/attachment_with_virus_check_status", item: fff.object, mount_name: :attachment + + = fff.input :attachment_cache, as: :hidden + + = fff.input :form_answer_id, as: :hidden, input_html: { value: @form_answer.id } + = fff.input :user_id, as: :hidden, input_html: { value: current_user.id } + diff --git a/app/views/form/support_letters/_support_letter.html.slim b/app/views/form/support_letters/_support_letter.html.slim deleted file mode 100644 index 16fb89cef..000000000 --- a/app/views/form/support_letters/_support_letter.html.slim +++ /dev/null @@ -1,34 +0,0 @@ -li.view-only - .govuk-grid-row - .govuk-grid-column-one-half - label.govuk-label - ' First Name - p.govuk-body - = support_letter.first_name - - .govuk-grid-row - .govuk-grid-column-one-half - label.govuk-label - ' Last Name - p.govuk-body - = support_letter.last_name - - .govuk-grid-row - .govuk-grid-column-one-half - label.govuk-label - ' Relationship to Nominee - p.govuk-body - = support_letter.relationship_to_nominee - - .govuk-grid-row - .govuk-grid-column-full - label.govuk-label - ' Letter of Support - span.support-letter-attachment-filename.govuk-body - - if support_letter.support_letter_attachment - - file = support_letter.support_letter_attachment - = render "shared/attachment_with_virus_check_status", item: file, - mount_name: :attachment - span.clear - - = button_to "Remove", form_form_answer_support_letter_path(@form_answer, support_letter), method: :delete, class: "govuk-button govuk-button--warning #{'read_only' if admin_in_read_only_mode?}", 'aria-label' => "Delete support letter from #{support_letter.first_name} #{support_letter.last_name}" diff --git a/app/views/form/support_letters/new.html.slim b/app/views/form/support_letters/new.html.slim deleted file mode 100644 index ae2bddb3a..000000000 --- a/app/views/form/support_letters/new.html.slim +++ /dev/null @@ -1,51 +0,0 @@ -- content_for :breadcrumbs do - li.govuk-breadcrumbs__list-item = link_to "Nominations", dashboard_path, class: 'govuk-breadcrumbs__link' - li.govuk-breadcrumbs__list-item = @form.title - -header.page-header.group.page-header-over-sidebar - div - h1.govuk-heading-xl - = @form.title - -.steps-progress-container - .steps-progress-content - = render 'qae_form/form_header', form: @form, current_step: "letters-of-support" - - .article-container.article-container-wider.step-article.step-current - article.group role="article" - div - fieldset.question-block - legend.govuk-label - span.steps.step-d-1 - span.visuallyhidden C 1 - span.todo C 1 - span class="govuk-body govuk-!-font-size-24 govuk-!-font-weight-bold govuk-!-display-block" - | New support letter - - ul.list-add - li - = simple_form_for [:form, @form_answer, @support_letter], html: { class: 'qae-form' } do |f| - .govuk-grid-row - .govuk-grid-column-one-half - = f.input :first_name, - input_html: { class: "form-control" } - = f.input :last_name, - input_html: { class: "form-control" } - = f.input :relationship_to_nominee, - input_html: { class: "form-control" } - - - f.object.support_letter_attachment || f.object.build_support_letter_attachment - = f.simple_fields_for f.object.support_letter_attachment do |ff| - = ff.input :attachment, - as: :file, - input_html: { class: "form-control" } - = f.submit "Submit letter of support", class: "govuk-button" - - footer - nav.pagination.no-border aria-label="Pagination" role="navigation" - ul.group - li.previous.previous-alternate - = link_to edit_form_url(id: params[:form_answer_id], step: "letters-of-support"), rel: "prev", title: "Navigate to previous part", class: 'govuk-button govuk-button--secondary' do - span.pagination-label Back - - = render "qae_form/steps_progress_bar", current_step: "letters-of-support" diff --git a/app/views/form/supporters/index.html.slim b/app/views/form/supporters/index.html.slim index 9d3c5c64a..ad955ba7c 100644 --- a/app/views/form/supporters/index.html.slim +++ b/app/views/form/supporters/index.html.slim @@ -15,6 +15,7 @@ h1.govuk-heading-xl article.group role="article" div - letters_intro_question = @step.questions.detect { |q| q.key == :supporter_letters_list } + - checkbox_questions = @step.questions.select { |q| q.key.in?(%i(independent_individual not_nominator)) } .question-block label.govuk-label @@ -35,13 +36,18 @@ h1.govuk-heading-xl = help.title.html_safe .govuk-details__text == help.text + + = simple_form_for [:form, @form_answer], url: [:form, @form_answer, :support_letters], method: :post, data: { turbo: false }, html: { class: 'qae-form' } do |f| + = hidden_field_tag :current_step_id, @step.title_to_param + = hidden_field_tag :next_step_id, @step.next.title_to_param + + ul.list-add.supporters-list + = render partial: "form/support_letters/form", locals: { f: f } - ul.list-add.supporters-list - - @form_answer.support_letters.each do |support_letter| - = render "form/support_letters/support_letter", support_letter: support_letter + - checkbox_questions.each do |question| + .govuk-form-group + = render partial: "qae_form/confirm_question", locals: { question: question } - = link_to "+ Add another support letter", new_form_form_answer_support_letter_path(@form_answer), class: "govuk-button govuk-button--secondary button-add" + = render partial: "form/support_letters/footer", locals: { f: f, step: @step } = render "qae_form/steps_progress_bar", current_step: "letters-of-support" - - = render "footer", step: @step diff --git a/app/views/qae_form/_supporter_fields.html.slim b/app/views/qae_form/_supporter_fields.html.slim index 531f51bd6..aee0fad3b 100644 --- a/app/views/qae_form/_supporter_fields.html.slim +++ b/app/views/qae_form/_supporter_fields.html.slim @@ -1,55 +1,37 @@ - persisted = supporter["support_letter_id"].present? || supporter["supporter_id"].present? -li.js-add-example class="#{'read-only js-support-letter-received' if persisted}" +- create_url = users_form_answer_support_letters_url(@form_answer) +- update_url = users_form_answer_support_letter_path(@form_answer, supporter["support_letter_id"]) if persisted +li[class=class_names("js-add-example", "js-support-letter-received" => persisted) data-create-url=create_url data-update-url=update_url] + label[class="govuk-label"] + span[class="govuk-body govuk-!-font-size-20 govuk-!-font-weight-bold govuk-!-display-block"] + = "Letter of Support #{index + 1}" + input.js-support-entry-id type="hidden" name="form[#{question.key}][#{index}][support_letter_id]" value=supporter["support_letter_id"] *possible_read_only_ops(question.step.opts[:id]) .js-system-tag data-new-hidden-input-name="form[#{question.key}][#{index}][support_letter_id]" .govuk-form-group label.govuk-label for="form[#{question.key}][#{index}][first_name]" - ' First Name + ' First Name: span.govuk-error-message - - input.js-support-letter-first-name.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][#{index}][first_name]" id="form[#{question.key}][#{index}][first_name]" type="text" value=supporter["first_name"] *possible_read_only_ops(question.step.opts[:id]) - p.govuk-body.visible-read-only = supporter["first_name"] - + input.js-support-letter-field.js-support-letter-first-name.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][#{index}][first_name]" id="form[#{question.key}][#{index}][first_name]" type="text" value=supporter["first_name"] *possible_read_only_ops(question.step.opts[:id]) .govuk-form-group label.govuk-label for="form[#{question.key}][#{index}][last_name]" - ' Surname + ' Surname: span.govuk-error-message - - input.js-support-letter-last-name.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][#{index}][last_name]" id="form[#{question.key}][#{index}][last_name]" type="text" value=supporter["last_name"] *possible_read_only_ops(question.step.opts[:id]) - p.govuk-body.visible-read-only = supporter["last_name"] - + input.js-support-letter-field.js-support-letter-last-name.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][#{index}][last_name]" id="form[#{question.key}][#{index}][last_name]" type="text" value=supporter["last_name"] *possible_read_only_ops(question.step.opts[:id]) .govuk-form-group label.govuk-label for="form[#{question.key}][#{index}][relationship_to_nominee]" - ' Relationship to Nominee + ' Relationship to Group: span.govuk-error-message + input.js-support-letter-field.js-support-letter-relationship-to-nominee.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][#{index}][relationship_to_nominee]" id="form[#{question.key}][#{index}][relationship_to_nominee]" type="text" value=supporter["relationship_to_nominee"] *possible_read_only_ops(question.step.opts[:id]) - input.js-support-letter-relationship-to-nominee.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][#{index}][relationship_to_nominee]" id="form[#{question.key}][#{index}][relationship_to_nominee]" type="text" value=supporter["relationship_to_nominee"] *possible_read_only_ops(question.step.opts[:id]) - p.govuk-body.visible-read-only = supporter["relationship_to_nominee"] .govuk-form-group label.govuk-label for="form[#{question.key}][#{index}][letter_of_support]" - ' Letter of Support + = "Upload Letter of Support #{index + 1}" span.govuk-error-message - input class="js-trigger-autosave js-support-letter-attachment govuk-input medium" name="form[#{question.key}][#{index}][letter_of_support]" id="form[#{question.key}][#{index}][letter_of_support]" type='file' *possible_read_only_ops(question.step.opts[:id]) + input class="js-support-letter-field js-trigger-autosave js-support-letter-attachment govuk-input medium" name="form[#{question.key}][#{index}][letter_of_support]" id="form[#{question.key}][#{index}][letter_of_support]" type='file' *possible_read_only_ops(question.step.opts[:id]) - if supporter['letter_of_support'].present? - = render "support_letters/attachment", question: question, - index: index, - attachment_id: supporter['letter_of_support'] - - p - button.govuk-button.js-save-collection class=(persisted ? "visuallyhidden" : "") data-save-collection-url=users_form_answer_support_letters_url(@form_answer) - | Submit letter of support - - - if current_form_is_editable? && !current_lieutenant && !current_assessor - - if persisted - - if supporter["support_letter_id"].present? && @form_answer.support_letters.find_by_id(supporter["support_letter_id"]) - - url = users_form_answer_support_letter_path(form_answer_id: @form_answer.id, id: supporter["support_letter_id"]) - - else - - url = "#" - - if current_user || policy(:support_letter).can_remove? - = link_to "Remove", url, class: "govuk-button govuk-button--warning remove-supporter remove-link js-remove-link", data: { url: url }, 'aria-label' => "Delete support letter from #{supporter["first_name"]} #{supporter["last_name"]}" - - else - = link_to "Remove", "#", class: "govuk-button govuk-button--warning remove-supporter remove-link js-remove-link govuk-!-display-none", data: { url: "#" }, 'aria-label' => "#" + = render "support_letters/attachment", question: question, index: index, attachment_id: supporter['letter_of_support'] diff --git a/app/views/qae_form/_supporter_fields_placeholder.html.slim b/app/views/qae_form/_supporter_fields_placeholder.html.slim index b95578a8b..1eb001785 100644 --- a/app/views/qae_form/_supporter_fields_placeholder.html.slim +++ b/app/views/qae_form/_supporter_fields_placeholder.html.slim @@ -1,30 +1,34 @@ li.js-add-example class="govuk-!-display-none" + label[class="govuk-label"] + span[class="govuk-body govuk-!-font-size-20 govuk-!-font-weight-bold govuk-!-display-block"] + = "Letter of Support #{index + 1}" + input.js-support-entry-id type="hidden" name="form[#{question.key}][{index}][support_letter_id]" disabled=true .js-system-tag data-new-hidden-input-name="form[#{question.key}][{index}][support_letter_id]" .govuk-form-group label.govuk-label for="form[#{question.key}][{index}][first_name]" - ' First Name + ' First Name: span.govuk-error-message input.js-support-letter-first-name.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][{index}][first_name]" id="form[#{question.key}][{index}][first_name]" type="text" disabled=true p.govuk-body.visible-read-only .govuk-form-group label.govuk-label for="form[#{question.key}][{index}][last_name]" - ' Surname + ' Surname: span.govuk-error-message input.js-support-letter-last-name.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][{index}][last_name]" id="form[#{question.key}][{index}][last_name]" type="text" disabled=true p.govuk-body.visible-read-only .govuk-form-group label.govuk-label for="form[#{question.key}][{index}][relationship_to_nominee]" - ' Relationship to Nominee + ' Relationship to Group: span.govuk-error-message input.js-support-letter-relationship-to-nominee.js-trigger-autosave.govuk-input autocomplete="off" class="js-trigger-autosave medium" name="form[#{question.key}][{index}][relationship_to_nominee]" id="form[#{question.key}][{index}][relationship_to_nominee]" type="text" disabled=true p.govuk-body.visible-read-only .govuk-form-group label.govuk-label for="form[#{question.key}][{index}][letter_of_support]" - ' Letter of Support + = "Upload Letter of Support #{index + 1}" span.govuk-error-message input class="js-trigger-autosave js-support-letter-attachment govuk-input medium" name="form[#{question.key}][{index}][letter_of_support]" id="form[#{question.key}][{index}][letter_of_support]" type='file' disabled=true diff --git a/app/views/qae_form/_supporters_question.html.slim b/app/views/qae_form/_supporters_question.html.slim index f01f627d6..81ae6406f 100644 --- a/app/views/qae_form/_supporters_question.html.slim +++ b/app/views/qae_form/_supporters_question.html.slim @@ -1,17 +1,5 @@ input name="form[#{question.key}][array]" value="true" type="hidden" *possible_read_only_ops(question.step.opts[:id]) ul.list-add.supporters-list data-need-to-clear-example=true data-add-limit=question.limit data-attachments-url=(users_form_answer_support_letter_attachments_path(@form_answer)) data-example-has-file-field=true - = render 'qae_form/supporter_fields_placeholder', question: question - - if question.entities.present? - - if question.entities.count < question.default.to_i - - question.entities.each_with_index do |supporter, index| - = render 'qae_form/supporter_fields', question: question, supporter: supporter, index: index - - else - - question.entities.each_with_index do |supporter, index| - = render 'qae_form/supporter_fields', question: question, supporter: supporter, index: index - - else - - (0...question.default.to_i).each do |index| - = render 'qae_form/supporter_fields', question: question, supporter: {}, index: index + - question.entities.each_with_index do |supporter, index| + = render 'qae_form/supporter_fields', question: question, supporter: supporter, index: index -- if current_form_is_editable? - a.govuk-button.govuk-button--secondary.button-add.js-button-add href="#" *possible_read_only_ops(question.step.opts[:id]) - | Add another letter of support diff --git a/app/views/support_letters/_attachment.html.slim b/app/views/support_letters/_attachment.html.slim index 7011af6b8..611b93a17 100644 --- a/app/views/support_letters/_attachment.html.slim +++ b/app/views/support_letters/_attachment.html.slim @@ -1,6 +1,5 @@ - file = support_letter_attachments[attachment_id.to_i] p.govuk-body.support-letter-attachment-filename - = render "shared/attachment_with_virus_check_status", item: file, - mount_name: :attachment + = render "shared/attachment_with_virus_check_status", item: file, mount_name: :attachment input.js-support-letter-attachment-id type="hidden" name="form[#{question.key}][#{index}][letter_of_support]" value=attachment_id *possible_read_only_ops diff --git a/config/routes.rb b/config/routes.rb index ec60f7ded..e9bb73c10 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -93,7 +93,7 @@ resource :list_of_procedures, only: [:create, :destroy] resource :support_letter_attachments, only: :create resources :supporters, only: [:create, :destroy] - resources :support_letters, only: [:create, :show, :destroy] + resources :support_letters, only: [:create, :update, :show, :destroy] end resources :form_answer_feedbacks, only: [:show] end @@ -104,7 +104,7 @@ namespace :form do resources :form_answers do resources :supporters, only: [:new, :create, :index, :destroy] - resources :support_letters, only: [:new, :create, :destroy] + resources :support_letters, only: [:create] resources :form_attachments, only: [:index, :new, :create, :destroy] end end diff --git a/forms/award_years/v2025/qavs/qavs_step3.rb b/forms/award_years/v2025/qavs/qavs_step3.rb index e10e928fa..f0308e6be 100644 --- a/forms/award_years/v2025/qavs/qavs_step3.rb +++ b/forms/award_years/v2025/qavs/qavs_step3.rb @@ -9,27 +9,40 @@ def qavs_step3 supporters :supporter_letters_list, "" do ref "C 1" context %( - -Please obtain two different letters that endorse the nominated group's contribution from people who are familiar with its work.
-- Supporters must not be volunteers or paid workers in the group. Each letter should be no more than 500 words. The letters should be about the whole group, rather than just one volunteer and should help to show how its work is outstanding. -
-Please list below the names of the supporters and their relationship (if any) to the group.
- ) - hint "What are the allowed file formats?", %( -- Letter of support must be no larger than 5 MB. -
-
- They can be:
-
- Images in jpg, jpeg and png formats;
-
- Files in doc, docx, odt, pdf and txt formats.
+
Letters of support are an essential part of your nomination, as they help to clarify and explain the impact of the nominated group’s work in the local community. You will need to provide 2 letters of support alongside your nomination.
+For more information on what letters can cover, please see the Letters of Support page on our website.
+Key criteria:
+For each letter uploaded below, please note the letter writer’s relationship to the group, for example: a beneficiary of the group, local resident or member of a partner charity.
+Once uploaded, all files are saved automatically. If you make a mistake and upload the wrong letter, please use the same button to upload the correct file as it will automatically replace the previous version.
) classes "question-support-uploads" limit 2 - default 1 + default 2 + end + + confirm :independent_individual, "" do + required + text -> do + %( + I can confirm that these letters were written by individuals independent of the group. + ) + end + end + + confirm :not_nominator, "" do + required + text -> do + %( + I can confirm that these letters were not written by the nominator. + ) + end end end end diff --git a/forms/qae_form_builder/supporters_question.rb b/forms/qae_form_builder/supporters_question.rb index 67a55a3d8..5933bf5fa 100644 --- a/forms/qae_form_builder/supporters_question.rb +++ b/forms/qae_form_builder/supporters_question.rb @@ -39,5 +39,15 @@ class SupportersQuestion < Question end class SupportersQuestionDecorator < MultiQuestionDecorator + def entities + super + + collection = [].fill({}, 0, limit) + @entities.each_with_index do |record, idx| + collection[idx] = record + end + + @entities = collection + end end end diff --git a/spec/fixtures/form_answer_document_with_review_audit_certificate_criteria.json b/spec/fixtures/form_answer_document_with_review_audit_certificate_criteria.json index f8b7475ed..800f9e9b2 100644 --- a/spec/fixtures/form_answer_document_with_review_audit_certificate_criteria.json +++ b/spec/fixtures/form_answer_document_with_review_audit_certificate_criteria.json @@ -30,7 +30,6 @@ "employees_4of5":"", "employees_5of5":"", "head_job_title":"asdasd", - "parent_company":"asdasd", "sic_code":"0111", "net_profit_1of2":"122", "net_profit_1of5":"", @@ -133,7 +132,6 @@ "development_performance":"sad", "financial_year_date_day":"1", "leadership_contribution":"asdasd", - "parent_ultimate_control":"yes", "head_of_business_honours":"sadasd", "invoicing_unit_relations":"", "organization_address_region":"East", diff --git a/spec/fixtures/form_answer_qavs.json b/spec/fixtures/form_answer_qavs.json index 11686e905..d87fcc9d9 100644 --- a/spec/fixtures/form_answer_qavs.json +++ b/spec/fixtures/form_answer_qavs.json @@ -113,6 +113,9 @@ } ], + "independent_individual": "yes", + "not_nominator": "yes", + "nominator_title": "Mr", "nominator_name": "Nominator", "nominator_address_building": "94", diff --git a/spec/fixtures/form_answer_qavs_with_la.json b/spec/fixtures/form_answer_qavs_with_la.json index 3a3fbd420..2bafd9811 100644 --- a/spec/fixtures/form_answer_qavs_with_la.json +++ b/spec/fixtures/form_answer_qavs_with_la.json @@ -113,6 +113,9 @@ } ], + "independent_individual": "yes", + "not_nominator": "yes", + "nominator_title": "Mr", "nominator_name": "Nominator", "nominator_address_building": "94",