From a4e50f2b873458e3036db1a6b3e6afb58d4b10b3 Mon Sep 17 00:00:00 2001 From: Louis Kirkham <65811538+TheDancingClown@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:27:52 +0100 Subject: [PATCH] Revert "Re-work appraisal form submissions" --- .../javascripts/admin/form_answers.js.coffee | 34 +++- app/assets/stylesheets/admin/base.scss | 5 - .../controllers/appraisal_form_controller.js | 189 ------------------ app/models/assessor_assignment.rb | 27 +-- ...section_appraisal_form_moderated.html.slim | 4 +- .../_section_appraisal_form_primary.html.slim | 4 +- ...section_appraisal_form_secondary.html.slim | 4 +- .../_section_case_summary.html.slim | 13 +- .../_application_background_section.html.slim | 2 +- .../_case_summary_submit_block.html.slim | 15 +- .../_non_rag_section.html.slim | 4 +- .../_rag_section.html.slim | 4 +- .../_submit_appraisal_form.html.slim | 15 +- .../_verdict_section.html.slim | 4 +- 14 files changed, 57 insertions(+), 267 deletions(-) delete mode 100644 app/javascript/controllers/appraisal_form_controller.js diff --git a/app/assets/javascripts/admin/form_answers.js.coffee b/app/assets/javascripts/admin/form_answers.js.coffee index 4f0550d00d..d36bc6d886 100644 --- a/app/assets/javascripts/admin/form_answers.js.coffee +++ b/app/assets/javascripts/admin/form_answers.js.coffee @@ -336,7 +336,29 @@ ready = -> if (element) element.classList.add('form-edit') - $(document).on "click", ".form-save-link:not(.js-form-save-link)", (e) -> + $('.submit-assessment').on 'ajax:error', (e, data, status, xhr) -> + panel = this.closest('.panel-body') + errors = data.responseJSON + + removeExistingErrorMessages(panel) + + Object.entries(errors).forEach ([key, values]) -> + field = panel.querySelector("[name*='[#{key}]']") + if field and shouldValidateField(field) + showErrorForInvalidField(field, values) + + $(".submit-assessment").on "ajax:success", (e, data, status, xhr) -> + panel = this.closest('.panel-body') + message = "Assessment submitted" + if panel.closest(".panel-collapse").classList.contains('section-case-summary') + message = "Case summary submitted" + + removeExistingErrorMessages(panel) + panel.insertAdjacentHTML('afterbegin', buildBannerHtml(message, 'success')) + + $(this).find('input:submit').remove() + + $(document).on "click", ".form-save-link", (e) -> link = $(this) e.preventDefault() formGroup = link.closest(".form-group") @@ -371,11 +393,11 @@ ready = -> input.val(updatedSection) form.submit() else - if area.first().val().length - formGroup.find(".form-value p:first").html(area.first().val().replace(/\n/g, '
')) - if area.last().val().length - formGroup.find(".form-value p:last").html(area.last().val().replace(/\n/g, '
')) - form.submit() + if area.first().val().length + formGroup.find(".form-value p:first").html(area.first().val().replace(/\n/g, '
')) + if area.last().val().length + formGroup.find(".form-value p:last").html(area.last().val().replace(/\n/g, '
')) + form.submit() $("#new_review_audit_certificate input[type='radio']").on "change", -> area = $(".audit-cert-description") diff --git a/app/assets/stylesheets/admin/base.scss b/app/assets/stylesheets/admin/base.scss index adb156c9e1..1bbe32c8b5 100644 --- a/app/assets/stylesheets/admin/base.scss +++ b/app/assets/stylesheets/admin/base.scss @@ -1619,11 +1619,6 @@ label.govuk-label.govuk-checkboxes__label.boolean.optional.govuk-label { } } - .rag-error { - background-color: #f2dede; - color: #a94442 !important; - } - .rag-blank { &, a, diff --git a/app/javascript/controllers/appraisal_form_controller.js b/app/javascript/controllers/appraisal_form_controller.js deleted file mode 100644 index 50835dc495..0000000000 --- a/app/javascript/controllers/appraisal_form_controller.js +++ /dev/null @@ -1,189 +0,0 @@ -export default class extends ApplicationController { - static values = { - success: String, - }; - - connect() {} - - success(event) { - return this.handleSuccess(event); - } - - error(event) { - return this.handleError(event); - } - - handleSuccess = ({ target }) => { - const panel = target.closest('.panel-body'); - - this.resetErrors(panel); - - const message = this.hasSuccessValue ? this.successValue : 'Success!'; - const [alert, identifier] = this.createAlert('success', message); - - panel.insertAdjacentHTML('afterbegin', alert); - - const template = this.element.querySelector('[data-role=template]'); - - if ('content' in template) { - const replacement = template.content.cloneNode(true); - target.replaceWith(replacement.firstChild); - } else { - target.remove(); - } - }; - - handleError = (event) => { - const { - target, - detail: { responseJSON: errors }, - } = event; - const panel = target.closest('.panel-body'); - - this.resetErrors(panel); - - Object.entries(errors).forEach(([key, values]) => { - const field = panel.querySelector(`[name*='[${key}]']`); - const container = field.closest('.form-container'); - - if (field && this.shouldValidateField(field)) { - this.showFieldErrors(field, values); - } - - if (key && key.endsWith('_rate')) { - const button = container.querySelector('label button'); - if (button) button.classList.add('rag-error'); - } else { - if (!this.visible(field)) { - const target = container.querySelector('.form-edit-link'); - if (target) $(target).trigger('click'); - } - } - }); - }; - - stash = (event) => { - event.preventDefault(); - event.stopPropagation(); - - const { target: button } = event; - const wrapper = button.closest('.form-group'); - const form = wrapper.closest('form'); - const textarea = Array.from(wrapper.querySelectorAll('textarea')).filter(this.visible); - - if (textarea.length > 1) { - for (let idx = 0; idx < textarea.length; idx++) { - LS.removeItem(textarea[idx].dataset.autosaveKey); - } - } else { - LS.removeItem(textarea[0].dataset.autosaveKey); - } - - wrapper.classList.remove('form-edit'); - - if (Array.from(wrapper.querySelectorAll('.form-value p[data-for]')).length > 0) { - Array.from(wrapper.querySelectorAll('.form-value p[data-for]')).forEach((el) => { - let identifier = el.dataset.for; - let element = document.querySelector(`#${identifier}`); - - if (element) el.innerHTML = element.value; - }); - - return form.submit(); - } else if (textarea.length === 1) { - let _textarea = textarea[0]; - - if (_textarea.value.length) { - const panel = event.target.closest('.panel-body'); - const value = _textarea.value.replace(/\n/g, '
'); - const updatedValue = button.dataset.updatedSection; - - wrapper.querySelector('.form-value p').innerHTML = value; - - panel.querySelector('.field-with-errors')?.classList?.remove('field-with-errors'); - panel.querySelector('.feedback-holder')?.classList?.remove('error'); - panel.querySelector('.btn-rag > button')?.classList?.remove('rag-error'); - - Array.from(wrapper.querySelectorAll('textarea')).forEach((el) => { - if (el.value && el.value.length) { - return el.closest('.input')?.classList?.remove('field-with-errors'); - } - }); - - if (updatedValue) { - const input = form.querySelector("input[name='updated_section']"); - - if (input) { - input.value = updatedValue; - } - } - - return form.submit(); - } - } else { - if (textarea[0] && textarea[0].value.length) { - const value = textarea[0].value.replace(/\n/g, '
'); - Array.from(wrapper.querySelectorAll('.form-value p'))[0].innerHTML = value; - } - - if (textarea[-1] && textarea[-1].value.length) { - const value = textarea[-1].value.replace(/\n/g, '
'); - Array.from(wrapper.querySelectorAll('.form-value p'))[-1].innerHTML = value; - } - - return form.submit(); - } - }; - - resetErrors(element) { - element.querySelectorAll('.field-with-errors').forEach((el) => el.classList.remove('field-with-errors')); - element.querySelectorAll('.rag-error').forEach((el) => el.classList.remove('rag-error')); - element.querySelectorAll('[aria-errormessage]').forEach((el) => el.removeAttribute('aria-errormessage')); - element.querySelectorAll('.alert').forEach((el) => el.remove()); - } - - shouldValidateField(field) { - return !field.disabled && field.type !== void 0 && !['file', 'reset', 'submit', 'button'].includes(field.type); - } - - showFieldErrors(field, errors, selector) { - if (selector == null) { - selector = '.form-container'; - } - - const container = field.closest(selector); - const group = field.closest('.govuk-form-group'); - - if (group) { - group.classList.add('field-with-errors'); - } - - if (container) { - return errors.forEach((message) => { - const [alert, identifier] = this.createAlert('danger', message); - field.setAttribute('aria-errormessage', identifier); - return container.insertAdjacentHTML('afterbegin', alert); - }); - } - } - - createAlert = (type, message) => { - const id = 'alert__' + String(Math.random()).slice(2, -1); - const element = ` - - `; - - return [element, id]; - }; - - visible(field) { - return ( - !field.hidden && (!field.type || field.type != 'hidden') && (field.offsetWidth > 0 || field.offsetHeight > 0) - ); - } -} diff --git a/app/models/assessor_assignment.rb b/app/models/assessor_assignment.rb index afe8d26884..5952da3a9d 100644 --- a/app/models/assessor_assignment.rb +++ b/app/models/assessor_assignment.rb @@ -152,13 +152,7 @@ def not_submitted_or_not_locked? def award_specific_attributes struct.diff(form_answer, moderated?).each do |att| if public_send(att).present? - message = if att.ends_with?("_rate") - "RAG rating for '#{section_name(att)}' cannot be present for this Award Type" - else - "An appraisal comment for '#{section_name(att)}' cannot be present for this Award Type" - end - - errors.add(att, message: message) + errors.add(att, "cannot be present for this Award Type") end end end @@ -168,13 +162,7 @@ def mandatory_fields_for_submitted struct.meths_for_award_type(form_answer, moderated?).each do |meth| if public_send(meth).blank? - message = if meth.ends_with?("_rate") - "RAG rating is required for '#{section_name(meth)}'. Select an option from the dropdown list." - else - "An appraisal comment is required for '#{section_name(meth)}' and must be filled in." - end - - errors.add(meth, message: message) + errors.add(meth, "cannot be blank for submitted assessment") end end end @@ -186,8 +174,7 @@ def validate_rate(rate_type) c = "#{rate_type.upcase}_ALLOWED_VALUES" if val && !struct.const_get(c).include?(val) sect_name = struct.rate(section) - message = "#{rate_type} field for '#{section_name(section)}' has not permitted value." - errors.add(sect_name, message: message) + errors.add(sect_name, "#{rate_type} field has not permitted value") end end end @@ -196,14 +183,6 @@ def section_rate(section) public_send(struct.rate(section)) end - def section_name(key) - @_sections ||= struct.struct(form_answer).to_h - section_key = key.to_s.gsub(/_desc$/, "").gsub(/_rate$/, "") - if section = @_sections.dig(section_key.to_sym) - section[:label].gsub(/:$/, "") - end - end - def struct AppraisalForm end diff --git a/app/views/admin/form_answers/_section_appraisal_form_moderated.html.slim b/app/views/admin/form_answers/_section_appraisal_form_moderated.html.slim index de355293c6..4e34590b76 100644 --- a/app/views/admin/form_answers/_section_appraisal_form_moderated.html.slim +++ b/app/views/admin/form_answers/_section_appraisal_form_moderated.html.slim @@ -7,12 +7,12 @@ small = moderated_assessment.last_editor_info - #section-appraisal-form-moderated.section-appraisal-form.section-appraisal-form-moderated.panel-collapse.collapse[aria-labelledby="appraisal-form-moderated-heading" data-controller="appraisal-form" data-appraisal-form-success-value="Appraisal form (moderated) has been submitted"] + #section-appraisal-form-moderated.section-appraisal-form.section-appraisal-form-moderated.panel-collapse.collapse[aria-labelledby="appraisal-form-moderated-heading"] .panel-body[data-controller="inline-flash"] = simple_form_for([namespace_name, moderated_assessment], remote: true, authenticity_token: true, - html: { data: { type: "json", inline_flash_target: "form" } }) do |f| + html: { data: { type: "json", inline_flash_target: "form", controller: "html5-form-validation", html5_form_validation_selectors_value: ["textarea"] } }) do |f| = render_section(resource, f) = hidden_field_tag :updated_section diff --git a/app/views/admin/form_answers/_section_appraisal_form_primary.html.slim b/app/views/admin/form_answers/_section_appraisal_form_primary.html.slim index 8a5bdf7d40..12430e2f25 100644 --- a/app/views/admin/form_answers/_section_appraisal_form_primary.html.slim +++ b/app/views/admin/form_answers/_section_appraisal_form_primary.html.slim @@ -6,12 +6,12 @@ - if primary_assessment.last_editor_info.present? small = primary_assessment.last_editor_info - #section-appraisal-form-primary.section-appraisal-form.section-appraisal-form-primary.panel-collapse.collapse[aria-labelledby="appraisal-form-primary-heading" data-controller="appraisal-form" data-appraisal-form-success-value="Appraisal form (primary) has been submitted"] + #section-appraisal-form-primary.section-appraisal-form.section-appraisal-form-primary.panel-collapse.collapse aria-labelledby="appraisal-form-primary-heading" .panel-body[data-controller="inline-flash"] = simple_form_for([namespace_name, primary_assessment], remote: true, authenticity_token: true, - html: { data: { type: "json", inline_flash_target: "form" }, id: "primary_appraisal_form" }) do |f| + html: { data: { type: "json", inline_flash_target: "form", html5_form_validation_selectors_value: ["textarea"], controller: "html5-form-validation" }, id: "primary_appraisal_form" }) do |f| = hidden_field_tag :updated_section, nil, id: "primary_updated_section_hidden_field" = render_section(resource, f) diff --git a/app/views/admin/form_answers/_section_appraisal_form_secondary.html.slim b/app/views/admin/form_answers/_section_appraisal_form_secondary.html.slim index 7295176f9d..27e6acd617 100644 --- a/app/views/admin/form_answers/_section_appraisal_form_secondary.html.slim +++ b/app/views/admin/form_answers/_section_appraisal_form_secondary.html.slim @@ -6,12 +6,12 @@ - if secondary_assessment.last_editor_info.present? small = secondary_assessment.last_editor_info - #section-appraisal-form-secondary.section-appraisal-form.section-appraisal-form-secondary.panel-collapse.collapse[aria-labelledby="appraisal-form-secondary-heading" data-controller="appraisal-form" data-appraisal-form-success-value="Appraisal form (secondary) has been submitted"] + #section-appraisal-form-secondary.section-appraisal-form.section-appraisal-form-secondary.panel-collapse.collapse aria-labelledby="appraisal-form-secondary-heading" .panel-body[data-controller="inline-flash"] = simple_form_for([namespace_name, secondary_assessment], remote: true, authenticity_token: true, - html: { data: { type: "json", inline_flash_target: "form" }, id: "secondary_appraisal_form"}) do |f| + html: { data: { type: "json", inline_flash_target: "form", controller: "html5-form-validation", html5_form_validation_selectors_value: ["textarea"] }, id: "secondary_appraisal_form"}) do |f| = hidden_field_tag :updated_section, nil, id: "secondary_updated_section_hidden_field" = render_section(resource, f) diff --git a/app/views/admin/form_answers/_section_case_summary.html.slim b/app/views/admin/form_answers/_section_case_summary.html.slim index 309962a33e..7bc5b85389 100644 --- a/app/views/admin/form_answers/_section_case_summary.html.slim +++ b/app/views/admin/form_answers/_section_case_summary.html.slim @@ -11,10 +11,19 @@ - if assessment.editable.present? small = "Updated by #{message_author_name(assessment.editable)} - #{format_date(assessment.updated_at)}" - .panel-collapse.collapse[aria-labelledby="case-summary-heading-#{assessment.position}" id="section-case-summary-#{assessment.position}" class="section-case-summary-#{assessment.position}" data-controller="appraisal-form" data-appraisal-form-success-value="Case summary has been submitted"] + .panel-collapse.collapse aria-labelledby="case-summary-heading-#{assessment.position}" id="section-case-summary-#{assessment.position}" class="section-case-summary-#{assessment.position}" .panel-body[data-controller="inline-flash"] - = simple_form_for([namespace_name, assessment], remote: true, authenticity_token: true, html: { data: { inline_flash_target: "form" } }) do |f| + /.alert.alert-glyphicon.alert-info + span.glyphicon.glyphicon-info-sign + p.todo-placeholder + ' Some instructions on how to use this or what this section is about. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus. + + / Only show if Moderated Appraisal is submitted + / For Primary Assessor + / It becomes read-only for primary assessor after submission + + = simple_form_for([namespace_name, assessment], remote: true, authenticity_token: true, html: { data: { inline_flash_target: "form", controller: "html5-form-validation", html5_form_validation_selectors_value: ["textarea"] } }) do |f| = render partial: "admin/form_answers/appraisal_form_components/application_background_section", locals: { f: f} = render_section(resource, f) diff --git a/app/views/admin/form_answers/appraisal_form_components/_application_background_section.html.slim b/app/views/admin/form_answers/appraisal_form_components/_application_background_section.html.slim index 70ef64e0dc..1b49d9e47d 100644 --- a/app/views/admin/form_answers/appraisal_form_components/_application_background_section.html.slim +++ b/app/views/admin/form_answers/appraisal_form_components/_application_background_section.html.slim @@ -23,5 +23,5 @@ = link_to "#", class: "form-edit-link pull-right", data: { element_focus_target: "reveal" } span.glyphicon.glyphicon-pencil ' Edit - = link_to "Save", "#", class: "btn btn-primary form-save-link js-form-save-link pull-right if-no-js-hide", data: { action: "click->appraisal-form#stash" } + = link_to "Save", "#", class: "btn btn-primary form-save-link pull-right if-no-js-hide", data: { action: "click->html5-form-validation#validate" } .clear diff --git a/app/views/admin/form_answers/appraisal_form_components/_case_summary_submit_block.html.slim b/app/views/admin/form_answers/appraisal_form_components/_case_summary_submit_block.html.slim index f1b3a16e5d..377907f0cc 100644 --- a/app/views/admin/form_answers/appraisal_form_components/_case_summary_submit_block.html.slim +++ b/app/views/admin/form_answers/appraisal_form_components/_case_summary_submit_block.html.slim @@ -1,6 +1,6 @@ - if policy(assessment).can_be_submitted? || policy(assessment).can_be_re_submitted? - = form_tag(url_for([namespace_name, :assessment_submissions]), remote: true, authenticity_token: true, class: "submit-assessment", data: { action: "ajax:x:success->appraisal-form#success ajax:x:error->appraisal-form#error", type: "json" }) + = form_tag(url_for([namespace_name, :assessment_submissions]), remote: true, authenticity_token: true, class: "submit-assessment", "data-type" => "json") = hidden_field_tag :assessment_id, assessment.id .feedback-holder @@ -9,19 +9,6 @@ = submit_tag submit_case_summary_title(assessment), class: "btn btn-primary btn-confirm-submit" .clear - template[data-role='template'] - - if policy(assessment).admin_or_lead? - - unlock_url = namespace_name == :admin ? unlock_admin_assessment_submission_url(assessment) : unlock_assessor_assessment_submission_url(assessment) - - = form_tag unlock_url, method: :patch do - = hidden_field_tag :assessment_id, assessment.id - .feedback-holder.alert.alert-success - ' Case Summary Submitted - - .pull-right - = submit_tag "Unlock", class: "btn btn-primary" - .clear - - elsif assessment.submitted? - if policy(assessment).can_unlock? diff --git a/app/views/admin/form_answers/appraisal_form_components/_non_rag_section.html.slim b/app/views/admin/form_answers/appraisal_form_components/_non_rag_section.html.slim index b41eb85b86..3a16109334 100644 --- a/app/views/admin/form_answers/appraisal_form_components/_non_rag_section.html.slim +++ b/app/views/admin/form_answers/appraisal_form_components/_non_rag_section.html.slim @@ -26,6 +26,6 @@ span.glyphicon.glyphicon-pencil ' Edit .form-actions.text-right - = link_to "Cancel", "#", class: "btn btn-default form-cancel-link if-no-js-hide", data: { element_focus_target: "dismiss" } - = link_to "Save", "#", class: "btn btn-primary form-save-link js-form-save-link pull-right if-no-js-hide", data: { updated_section: section.desc, action: "click->appraisal-form#stash" } + = link_to "Cancel", "#", class: "btn btn-default form-cancel-link if-no-js-hide", data: { element_focus_target: "dismiss", action: "click->html5-form-validation#discard" } + = link_to "Save", "#", class: "btn btn-primary form-save-link pull-right if-no-js-hide", data: { action: "click->html5-form-validation#validate", updated_section: section.desc } .clear diff --git a/app/views/admin/form_answers/appraisal_form_components/_rag_section.html.slim b/app/views/admin/form_answers/appraisal_form_components/_rag_section.html.slim index 0af8748211..6747cf3735 100644 --- a/app/views/admin/form_answers/appraisal_form_components/_rag_section.html.slim +++ b/app/views/admin/form_answers/appraisal_form_components/_rag_section.html.slim @@ -46,6 +46,6 @@ span.glyphicon.glyphicon-pencil ' Edit .form-actions.text-right - = link_to "Cancel", "#", class: "btn btn-default form-cancel-link if-no-js-hide", data: { element_focus_target: "dismiss" } - = link_to "Save", "#", class: "btn btn-primary form-save-link js-form-save-link pull-right if-no-js-hide", data: { updated_section: section.desc, action: "click->appraisal-form#stash" } + = link_to "Cancel", "#", class: "btn btn-default form-cancel-link if-no-js-hide", data: { element_focus_target: "dismiss", action: "click->html5-form-validation#discard" } + = link_to "Save", "#", class: "btn btn-primary form-save-link pull-right if-no-js-hide", data: { action: "click->html5-form-validation#validate", updated_section: section.desc } .clear diff --git a/app/views/admin/form_answers/appraisal_form_components/_submit_appraisal_form.html.slim b/app/views/admin/form_answers/appraisal_form_components/_submit_appraisal_form.html.slim index afd2f9ee3f..ecf4400712 100644 --- a/app/views/admin/form_answers/appraisal_form_components/_submit_appraisal_form.html.slim +++ b/app/views/admin/form_answers/appraisal_form_components/_submit_appraisal_form.html.slim @@ -3,7 +3,7 @@ authenticity_token: true, remote: true, class: "submit-assessment", - data: { action: "ajax:x:success->appraisal-form#success ajax:x:error->appraisal-form#error", type: "json" }) + data: { type: "json" }) = hidden_field_tag :assessment_id, assessment.id, id: "#{assessment.position}_assessment_id_submit_appraisal_form_hidden_field" @@ -13,19 +13,6 @@ = submit_tag (assessment.submitted? ? "Re-submit appraisal" : "Submit appraisal"), class: "btn btn-primary btn-confirm-submit" .clear - template[data-role='template'] - - if policy(assessment).admin_or_lead? - - unlock_url = namespace_name == :admin ? unlock_admin_assessment_submission_url(assessment) : unlock_assessor_assessment_submission_url(assessment) - - = form_tag unlock_url, method: :patch do - = hidden_field_tag :assessment_id, assessment.id, id: "#{assessment.position}_assessment_id_unlock_appraisal_form_hidden_field" - .feedback-holder.alert.alert-success - ' Assessment submitted - - .pull-right - = submit_tag "Unsubmit", class: "btn btn-primary" - .clear - - elsif assessment.submitted? - if policy(assessment).can_unlock? diff --git a/app/views/admin/form_answers/appraisal_form_components/_verdict_section.html.slim b/app/views/admin/form_answers/appraisal_form_components/_verdict_section.html.slim index 4eacdcbd27..c0102babf6 100644 --- a/app/views/admin/form_answers/appraisal_form_components/_verdict_section.html.slim +++ b/app/views/admin/form_answers/appraisal_form_components/_verdict_section.html.slim @@ -44,6 +44,6 @@ span.glyphicon.glyphicon-pencil ' Edit .form-actions.text-right - = link_to "Cancel", "#", class: "btn btn-default form-cancel-link if-no-js-hide", data: { element_focus_target: "dismiss" } - = link_to "Save", "#", class: "btn btn-primary form-save-link pull-right if-no-js-hide" + = link_to "Cancel", "#", class: "btn btn-default form-cancel-link if-no-js-hide", data: { element_focus_target: "dismiss", action: "click->html5-form-validation#discard" } + = link_to "Save", "#", class: "btn btn-primary form-save-link pull-right if-no-js-hide", data: { action: "click->html5-form-validation#validate" } .clear