Skip to content

Commit

Permalink
Validating A levels when the course is teacher degree apprenticeship
Browse files Browse the repository at this point in the history
We need to add a validation for the A levels when publishing a course.

I added the option render_errors: with default being true to avoid
breaking existing code but passing false to A levels Because:

* The A levels are a multi step form and I need to inject the error
on the row in any way is described in the card
* The row has the wizard step name attached to the link so different
from the way GCSEs or degrees or others are doing when publishing
  • Loading branch information
tomas-stefano committed Jul 3, 2024
1 parent edf18bc commit dd9d3d1
Show file tree
Hide file tree
Showing 13 changed files with 563 additions and 26 deletions.
26 changes: 20 additions & 6 deletions app/components/a_level_row_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
<% if course.a_levels_requirements_answered? %>
<% if has_errors? %>
<%= govuk_inset_text(classes: "app-inset-text--narrow-border app-inset-text--error") do %>
<% a_level_errors.each do |a_level_error| %>
<p class="govuk-heading-s app-inset-text__title">
<%= t("course.#{wizard_step(a_level_error)}.heading") %>
</p>
<p class="govuk-body">
<%= govuk_link_to(
@errors[a_level_error],
enrichment_error_url(course:, provider_code:, field: a_level_error.to_s, message: @errors[a_level_error])
) %>
</p>
<% end %>
<% end %>
<% elsif minimum_a_level_completed? %>
<% if @course.a_level_requirements.present? %>
<% Array(@course.a_level_subject_requirements).map do |a_level_subject_requirement| %>
<p class="govuk-body">
Expand Down Expand Up @@ -26,17 +40,17 @@
<% else %>
<%= a_level_not_required_content %>
<% end %>

<% else %>
<%= govuk_inset_text(classes: inset_text_css_classes) do %>
<p class="govuk-heading-s app-inset-text__title"><%= t("publish.providers.courses.description_content.a_levels_heading") %></p>
<%= govuk_inset_text(classes: "app-inset-text--narrow-border app-inset-text--important") do %>
<p class="govuk-heading-s app-inset-text__title">
<%= t("publish.providers.courses.description_content.a_levels_heading") %>
</p>
<p class="govuk-body">
<%= govuk_link_to t("publish.providers.courses.description_content.enter_a_levels"),
publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path(
course.provider.provider_code,
course.provider.recruitment_cycle_year,
course.course_code,
display_errors: has_errors? ? true : nil
course.course_code
) %>
</p>
<% end %>
Expand Down
36 changes: 31 additions & 5 deletions app/components/a_level_row_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,21 @@
class ALevelRowComponent < ViewComponent::Base
attr_reader :course, :errors

delegate :provider, to: :course
delegate :provider_code, to: :provider
include ViewHelper

A_LEVEL_ERRORS = %i[
a_level_requirements
a_level_subject_requirements
accept_pending_a_level
accept_a_level_equivalency
].freeze

def initialize(course:, errors: nil)
super
@course = course
@errors = errors&.values&.flatten
@errors = errors
end

def a_level_not_required_content
Expand Down Expand Up @@ -34,11 +45,26 @@ def a_level_equivalency_summary_content
I18n.t("course.a_level_equivalencies.row.#{@course.accept_a_level_equivalency?}") unless @course.accept_a_level_equivalency.nil?
end

def inset_text_css_classes
'app-inset-text--narrow-border app-inset-text--important'
def has_errors?
@errors.present? && a_level_errors.any?
end

def has_errors?
false
def a_level_errors
Array(@errors.keys & A_LEVEL_ERRORS)
end

def wizard_step(a_level_error)
{
a_level_requirements: :are_any_a_levels_required_for_this_course,
a_level_subject_requirements: :what_a_level_is_required,
accept_pending_a_level: :consider_pending_a_level,
accept_a_level_equivalency: :a_level_equivalencies
}.with_indifferent_access[a_level_error]
end

def minimum_a_level_completed?
!course.a_level_requirements.nil? &&
(course.a_level_requirements.blank? ||
(course.a_level_requirements.present? && course.a_level_subject_requirements.present?))
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def new
course: @course,
step_params:
)

@wizard.valid_step? if params[:display_errors].present?
end

def create
Expand Down
5 changes: 2 additions & 3 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ def enrichment_error_link(model, field, error)
end

# TODO: refactor enrichment_summary method to not use an instance variable
def enrichment_summary(summary_list, model, key, value, fields, action_path: nil, action_visually_hidden_text: nil)
def enrichment_summary(summary_list, model, key, value, fields, action_path: nil, action_visually_hidden_text: nil, render_errors: true)
action = render_action(action_path, action_visually_hidden_text || key.downcase)

if fields.any? { |field| @errors&.key? field.to_sym }
errors = fields.map do |field|
@errors[field.to_sym]&.map { |error| enrichment_error_link(model, field, error) }
end.flatten

value = raw(*errors)
value = raw(*errors) if render_errors.present?
action = nil
end

Expand Down
26 changes: 25 additions & 1 deletion app/helpers/view_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,31 @@ def enrichment_error_url(provider_code:, course:, field:, message: nil)
sites: "#{base}/schools?display_errors=true",
study_sites: (course.provider&.study_sites&.none? ? "#{provider_base}/study-sites" : "#{base}/study-sites").to_s,
accrediting_provider: accredited_provider_publish_provider_recruitment_cycle_course_path(course.provider_code, course.recruitment_cycle_year, course.course_code),
applications_open_from: "#{base}/applications-open"
applications_open_from: "#{base}/applications-open",
a_level_requirements: publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path(
course.provider_code,
course.provider.recruitment_cycle_year,
course.course_code,
display_errors: true
),
a_level_subject_requirements: publish_provider_recruitment_cycle_course_a_levels_what_a_level_is_required_path(
course.provider_code,
course.provider.recruitment_cycle_year,
course.course_code,
display_errors: true
),
accept_pending_a_level: publish_provider_recruitment_cycle_course_a_levels_consider_pending_a_level_path(
course.provider_code,
course.provider.recruitment_cycle_year,
course.course_code,
display_errors: true
),
accept_a_level_equivalency: publish_provider_recruitment_cycle_course_a_levels_a_level_equivalencies_path(
course.provider_code,
course.provider.recruitment_cycle_year,
course.course_code,
display_errors: true
)
}.with_indifferent_access[field]
end
end
Expand Down
1 change: 1 addition & 0 deletions app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ def self.entry_requirement_options_without_nil_choice
validate :validate_custom_age_range, on: %i[create new], if: -> { age_range_in_years.present? }
validate :accredited_provider_exists_in_current_cycle, on: :publish, unless: -> { self_accredited? }
validates_with UniqueCourseValidator, on: :new
validates_with ALevelCourseValidator, on: :publish, if: :teacher_degree_apprenticeship?

validates :name, :profpost_flag, :program_type, :qualification, :start_date, :study_mode, presence: true
validates :age_range_in_years, presence: true, on: %i[new create publish], unless: :further_education_course?
Expand Down
15 changes: 15 additions & 0 deletions app/validators/a_level_course_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class ALevelCourseValidator < ActiveModel::Validator
def validate(record)
return record.errors.add(:a_level_requirements, :blank) if record.a_level_requirements.nil?

return if record.a_level_requirements.blank? # No A level required

return record.errors.add(:a_level_subject_requirements, :blank) if record.a_level_subject_requirements.blank?

return record.errors.add(:accept_pending_a_level, :blank) if record.accept_pending_a_level.nil?

record.errors.add(:accept_a_level_equivalency, :blank) if record.accept_a_level_equivalency.nil?
end
end
11 changes: 8 additions & 3 deletions app/views/publish/courses/_description_content.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,14 @@
:course,
t("publish.providers.courses.description_content.a_levels_label"),
(render ALevelRowComponent.new(course:, errors: @errors)),
%w[a_levels_requirements],
action_path: publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path(@provider.provider_code, @provider.recruitment_cycle_year, course.course_code),
action_visually_hidden_text: "A levels"
%w[a_level_requirements a_level_subject_requirements accept_pending_a_level accept_a_level_equivalency],
action_path: publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path(
@provider.provider_code,
@provider.recruitment_cycle_year,
course.course_code
),
action_visually_hidden_text: "A levels",
render_errors: false
) %>
<% end %>

Expand Down
8 changes: 8 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,14 @@ en:
does_not_exist_in_cycle: "The accredited provider %{accredited_provider_code} does not exist in this cycle"
is_send:
inclusion: Select if this course has a special educational needs and disability (SEND) specialism
a_level_requirements:
blank: Enter A level requirements
a_level_subject_requirements:
blank: Enter A level requirements
accept_pending_a_level:
blank: Enter information on pending A levels
accept_a_level_equivalency:
blank: Enter A level equivalency test requirements
base:
duplicate: "This course already exists. You should add further schools for this course to the existing profile in Publish"
visa_sponsorship_not_publishable: "Select if visas can be sponsored"
Expand Down
Loading

0 comments on commit dd9d3d1

Please sign in to comment.