Browse Source

CLDC-3081 Update date input component (#2891)

* Add moj-frontend

* Use date picker component in log forms

* Refactor date_picker into component, add date_picker to location startdate

* Use date_picker for location deactivation periods

* Use date_picker in scheme deactivations

* Use date_picker for merge request date

* Fix missed tests

* lint

* Refactor
pull/2884/head^2
kosiakkatrina 5 days ago committed by GitHub
parent
commit
156c4b5b56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      app/components/check_answers_summary_list_card_component.rb
  2. 4
      app/controllers/check_errors_controller.rb
  3. 54
      app/controllers/form_controller.rb
  4. 12
      app/controllers/locations_controller.rb
  5. 4
      app/controllers/merge_requests_controller.rb
  6. 6
      app/controllers/schemes_controller.rb
  7. 5
      app/frontend/application.js
  8. 1
      app/frontend/styles/application.scss
  9. 2
      app/helpers/check_answers_helper.rb
  10. 2
      app/helpers/check_errors_helper.rb
  11. 8
      app/helpers/duplicate_logs_helper.rb
  12. 6
      app/helpers/form_page_helper.rb
  13. 2
      app/helpers/guidance_helper.rb
  14. 4
      app/helpers/tasklist_helper.rb
  15. 2
      app/models/form.rb
  16. 2
      app/models/form/lettings/pages/address_matcher.rb
  17. 2
      app/models/form/sales/pages/address_matcher.rb
  18. 4
      app/models/lettings_log.rb
  19. 4
      app/models/sales_log.rb
  20. 2
      app/views/check_errors/confirm_clear_all_answers.html.erb
  21. 2
      app/views/check_errors/confirm_clear_answer.html.erb
  22. 25
      app/views/components/_date_picker.html.erb
  23. 2
      app/views/duplicate_logs/_duplicate_log.html.erb
  24. 18
      app/views/form/_date_question.html.erb
  25. 4
      app/views/form/check_errors.html.erb
  26. 12
      app/views/locations/availability.erb
  27. 15
      app/views/locations/toggle_active.html.erb
  28. 4
      app/views/logs/delete_duplicates.html.erb
  29. 14
      app/views/merge_requests/merge_date.html.erb
  30. 12
      app/views/schemes/toggle_active.html.erb
  31. 1
      config/initializers/assets.rb
  32. 2
      config/locales/en.yml
  33. 2
      package.json
  34. 28
      spec/features/form/page_routing_spec.rb
  35. 4
      spec/features/form/validations_spec.rb
  36. 5
      spec/features/sales_log_spec.rb
  37. 8
      spec/features/schemes_helpers.rb
  38. 8
      spec/features/schemes_spec.rb
  39. 32
      spec/requests/form_controller_spec.rb
  40. 46
      spec/requests/locations_controller_spec.rb
  41. 8
      spec/requests/merge_requests_controller_spec.rb
  42. 16
      spec/requests/schemes_controller_spec.rb
  43. 6
      webpack.config.js
  44. 17
      yarn.lock

6
app/components/check_answers_summary_list_card_component.rb

@ -31,16 +31,16 @@ class CheckAnswersSummaryListCardComponent < ViewComponent::Base
def action_href(question, log)
referrer = question.displayed_as_answered?(log) ? "check_answers" : "check_answers_new_answer"
send("#{log.model_name.param_key}_#{question.page.id}_path", log, referrer:)
send("#{log.log_type}_#{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)
send("#{log.log_type}_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"])
send("#{log.log_type}_#{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

4
app/controllers/check_errors_controller.rb

@ -7,8 +7,8 @@ class CheckErrorsController < ApplicationController
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"])
@related_question_ids = params[@log.log_type].keys.reject { |id| id == "page_id" }
@page = @log.form.get_page(params[@log.log_type]["page_id"])
if params["clear_all"]
@questions_to_clear = @related_question_ids.map { |id|

54
app/controllers/form_controller.rb

@ -9,7 +9,7 @@ class FormController < ApplicationController
def submit_form
if @log
@page = form.get_page(params[@log.model_name.param_key][:page])
@page = form.get_page(params[@log.log_type][:page])
return render_check_errors_page if params["check_errors"]
shown_page_ids_with_unanswered_questions_before_update = @page.subsection.pages
@ -47,7 +47,7 @@ class FormController < ApplicationController
flash[:log_data] = responses_for_page
question_ids = (@log.errors.map(&:attribute) - [:base]).uniq
flash[:pages_with_errors_count] = question_ids.map { |id| @log.form.get_question(id, @log)&.page&.id }.compact.uniq.count
redirect_to send("#{@log.class.name.underscore}_#{@page.id}_path", @log, { referrer: request.params["referrer"], original_page_id: request.params["original_page_id"], related_question_ids: request.params["related_question_ids"] })
redirect_to send("#{@log.log_type}_#{@page.id}_path", @log, { referrer: request.params["referrer"], original_page_id: request.params["original_page_id"], related_question_ids: request.params["related_question_ids"] })
end
else
render_not_found
@ -136,11 +136,9 @@ private
def responses_for_page(page)
page.questions.each_with_object({}) do |question, result|
question_params = params[@log.model_name.param_key][question.id]
question_params = params[@log.log_type][question.id]
if question.type == "date"
day = params[@log.model_name.param_key]["#{question.id}(3i)"]
month = params[@log.model_name.param_key]["#{question.id}(2i)"]
year = params[@log.model_name.param_key]["#{question.id}(1i)"]
day, month, year = params[@log.log_type][question.id].split("/")
next unless [day, month, year].any?(&:present?)
result[question.id] = if Date.valid_date?(year.to_i, month.to_i, day.to_i) && year.to_i.positive?
@ -160,7 +158,7 @@ private
question.answer_keys_without_dividers.each do |option|
result[option] = question_params.include?(option) ? 1 : 0
end
else
elsif question.type != "date"
result[question.id] = question_params
end
@ -215,11 +213,11 @@ private
end
def previous_interruption_screen_page_id
params[@log.model_name.param_key]["interruption_page_id"]
params[@log.log_type]["interruption_page_id"]
end
def previous_interruption_screen_referrer
params[@log.model_name.param_key]["interruption_page_referrer_type"].presence
params[@log.log_type]["interruption_page_referrer_type"].presence
end
def page_has_duplicate_check_question
@ -229,7 +227,7 @@ private
def update_duplication_tracking
return unless page_has_duplicate_check_question
class_name = @log.class.name.underscore
class_name = @log.log_type
dynamic_duplicates = current_user.send(class_name.pluralize).duplicate_logs(@log)
if dynamic_duplicates.any?
@ -245,7 +243,7 @@ private
end
def successful_redirect_path(pages_to_check)
class_name = @log.class.name.underscore
class_name = @log.log_type
if is_referrer_type?("duplicate_logs") || is_referrer_type?("duplicate_logs_banner")
original_log = current_user.send(class_name.pluralize).find_by(id: from_referrer_query("original_log_id"))
@ -262,7 +260,7 @@ private
end
unless @log.duplicate_set_id.nil?
return send("#{@log.class.name.underscore}_duplicate_logs_path", @log, original_log_id: @log.id)
return send("#{@log.log_type}_duplicate_logs_path", @log, original_log_id: @log.id)
end
if is_referrer_type?("check_answers")
@ -275,25 +273,25 @@ private
elsif pages_to_check.any?
return redirect_path_to_question(pages_to_check[0], pages_to_check)
else
return send("#{@log.model_name.param_key}_#{form.subsection_for_page(@page).id}_check_answers_path", @log)
return send("#{@log.log_type}_#{form.subsection_for_page(@page).id}_check_answers_path", @log)
end
end
if previous_interruption_screen_page_id.present?
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)
return send("#{@log.log_type}_#{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"])
if params[@log.log_type]["check_errors"]
@page = form.get_page(params[@log.log_type]["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)
original_page_id = params[@log.log_type]["original_page_id"]
related_question_ids = params[@log.log_type]["related_question_ids"].split(" ")
return send("#{@log.log_type}_#{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"])
@page = form.get_page(params[@log.log_type]["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)
return send("#{@log.log_type}_#{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")
@ -306,7 +304,7 @@ private
def redirect_path_to_question(page_to_show, unanswered_pages)
remaining_pages = unanswered_pages.excluding(page_to_show)
remaining_page_ids = remaining_pages.any? ? remaining_pages.map(&:id).join(",") : nil
send("#{@log.class.name.underscore}_#{page_to_show.id}_path", @log, { referrer: "check_answers", unanswered_pages: remaining_page_ids })
send("#{@log.log_type}_#{page_to_show.id}_path", @log, { referrer: "check_answers", unanswered_pages: remaining_page_ids })
end
def pages_requiring_update(previously_visible_empty_page_ids)
@ -350,8 +348,8 @@ private
def question_missing_response?(responses_for_page, question)
if %w[checkbox validation_override].include?(question.type)
answered = question.answer_keys_without_dividers.map do |option|
session["fields"][option] = @log[option] = params[@log.model_name.param_key][question.id].include?(option) ? 1 : 0
params[@log.model_name.param_key][question.id].exclude?(option)
session["fields"][option] = @log[option] = params[@log.log_type][question.id].include?(option) ? 1 : 0
params[@log.log_type][question.id].exclude?(option)
end
answered.all?
else
@ -371,7 +369,7 @@ private
CONFIRMATION_PAGE_IDS = %w[uprn_confirmation uprn_selection].freeze
def deduplication_success_banner
deduplicated_log_link = "<a class=\"govuk-notification-banner__link govuk-!-font-weight-bold\" href=\"#{send("#{@log.class.name.underscore}_path", @log)}\">Log #{@log.id}</a>"
deduplicated_log_link = "<a class=\"govuk-notification-banner__link govuk-!-font-weight-bold\" href=\"#{send("#{@log.log_type}_path", @log)}\">Log #{@log.id}</a>"
changed_labels = {
property_postcode: "postcode",
lead_tenant_age: "lead tenant’s age",
@ -430,8 +428,8 @@ private
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(" ")
if params[@log.log_type]["clear_question_ids"].present?
question_ids = params[@log.log_type]["clear_question_ids"].split(" ")
question_ids.each do |question_id|
question = @log.form.get_question(question_id, @log)
next if question.subsection.id == "setup"
@ -440,7 +438,7 @@ private
@log.previous_la_known = nil if question.id == "ppostcode_full"
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) }
@questions = params[@log.log_type].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)

12
app/controllers/locations_controller.rb

@ -137,9 +137,7 @@ class LocationsController < ApplicationController
def availability; end
def update_availability
day = location_params["startdate(3i)"]
month = location_params["startdate(2i)"]
year = location_params["startdate(1i)"]
day, month, year = location_params["startdate"].split("/")
@location.startdate = if [day, month, year].none?(&:blank?) && Date.valid_date?(year.to_i, month.to_i, day.to_i)
Time.zone.local(year.to_i, month.to_i, day.to_i)
end
@ -258,7 +256,7 @@ private
end
def location_params
required_params = params.require(:location).permit(:postcode, :location_admin_district, :location_code, :name, :units, :type_of_unit, :mobility_type, "startdate(1i)", "startdate(2i)", "startdate(3i)").merge(scheme_id: @scheme.id)
required_params = params.require(:location).permit(:postcode, :location_admin_district, :location_code, :name, :units, :type_of_unit, :mobility_type, :startdate).merge(scheme_id: @scheme.id)
required_params[:postcode] = PostcodeService.clean(required_params[:postcode]) if required_params[:postcode]
required_params[:location_admin_district] = nil if required_params[:location_admin_district] == "Select an option"
required_params
@ -297,13 +295,9 @@ private
return
elsif params[:location_deactivation_period]["#{key}_type".to_sym] == "default"
return FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period
elsif params[:location_deactivation_period][key.to_sym].present?
return params[:location_deactivation_period][key.to_sym]
end
day = params[:location_deactivation_period]["#{key}(3i)"]
month = params[:location_deactivation_period]["#{key}(2i)"]
year = params[:location_deactivation_period]["#{key}(1i)"]
day, month, year = params[:location_deactivation_period][key.to_s].split("/")
return nil if [day, month, year].any?(&:blank?)
Time.zone.local(year.to_i, month.to_i, day.to_i) if Date.valid_date?(year.to_i, month.to_i, day.to_i)

4
app/controllers/merge_requests_controller.rb

@ -137,9 +137,7 @@ private
@merge_request.errors.add(:absorbing_organisation_id, :blank)
end
when "merge_date"
day = merge_request_params["merge_date(3i)"]
month = merge_request_params["merge_date(2i)"]
year = merge_request_params["merge_date(1i)"]
day, month, year = merge_request_params["merge_date"].split("/")
return @merge_request.errors.add(:merge_date, :blank) if [day, month, year].all?(&:blank?)

6
app/controllers/schemes_controller.rb

@ -356,13 +356,9 @@ private
return
elsif params[:scheme_deactivation_period]["#{key}_type".to_sym] == "default"
return FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period
elsif params[:scheme_deactivation_period][key.to_sym].present?
return params[:scheme_deactivation_period][key.to_sym]
end
day = params[:scheme_deactivation_period]["#{key}(3i)"]
month = params[:scheme_deactivation_period]["#{key}(2i)"]
year = params[:scheme_deactivation_period]["#{key}(1i)"]
day, month, year = params[:scheme_deactivation_period][key.to_s].split("/")
return nil if [day, month, year].any?(&:blank?)
Time.zone.local(year.to_i, month.to_i, day.to_i) if Date.valid_date?(year.to_i, month.to_i, day.to_i)

5
app/frontend/application.js

@ -14,11 +14,16 @@ import 'regenerator-runtime/runtime'
//
import { initAll as GOVUKFrontend } from 'govuk-frontend'
import { initAll as GOVUKPrototypeComponents } from '@x-govuk/govuk-prototype-components'
import { initAll as MOJFrontend } from '@ministryofjustice/frontend'
import './controllers'
import './cookie-banner'
import './styles/application.scss'
import 'moj-frontend'
import $ from 'jquery'
window.$ = $
require.context('govuk-frontend/dist/govuk/assets')
GOVUKFrontend()
GOVUKPrototypeComponents()
MOJFrontend()

1
app/frontend/styles/application.scss

@ -50,6 +50,7 @@ $govuk-breakpoints: (
@import "unread-notification";
@import "red-link";
@import "custom-rails-admin";
@import "node_modules/@ministryofjustice/frontend/moj/components/date-picker/date-picker";
// App utilities
.app-\!-colour-muted {

2
app/helpers/check_answers_helper.rb

@ -26,7 +26,7 @@ module CheckAnswersHelper
end
def next_incomplete_section_path(log, redirect_path)
"#{log.class.name.underscore}_#{redirect_path.underscore.tr('/', '_')}_path"
"#{log.log_type}_#{redirect_path.underscore.tr('/', '_')}_path"
end
private

2
app/helpers/check_errors_helper.rb

@ -6,6 +6,6 @@ module CheckErrorsHelper
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))
send("#{log.log_type}_#{question.page.id}_path", log, referrer: "check_errors", original_page_id: page.id, related_question_ids: applicable_questions.map(&:id))
end
end

8
app/helpers/duplicate_logs_helper.rb

@ -7,7 +7,7 @@ module DuplicateLogsHelper
return govuk_button_link_to "Keep this log and delete duplicates", url_for(
controller: "duplicate_logs",
action: "delete_duplicates",
"#{duplicate_log.class.name.underscore}_id": duplicate_log.id,
"#{duplicate_log.log_type}_id": duplicate_log.id,
original_log_id: original_log.id,
referrer: params[:referrer],
organisation_id: params[:organisation_id],
@ -16,7 +16,7 @@ module DuplicateLogsHelper
if params[:referrer] == "duplicate_logs_banner"
current_user.support? ? govuk_button_link_to("Review other duplicates", organisation_duplicates_path(organisation_id: params[:organisation_id], referrer: params[:referrer])) : govuk_button_link_to("Review other duplicates", duplicate_logs_path(referrer: params[:referrer]))
elsif !original_log.deleted?
govuk_button_link_to "Back to Log #{original_log.id}", send("#{original_log.class.name.underscore}_path", original_log)
govuk_button_link_to "Back to Log #{original_log.id}", send("#{original_log.log_type}_path", original_log)
else
type = duplicate_log.lettings? ? "lettings" : "sales"
govuk_button_link_to "Back to #{type} logs", url_for(duplicate_log.class)
@ -24,12 +24,12 @@ module DuplicateLogsHelper
end
def duplicate_logs_action_href(log, page_id, original_log_id)
send("#{log.model_name.param_key}_#{page_id}_path", log, referrer: "interruption_screen", original_log_id:)
send("#{log.log_type}_#{page_id}_path", log, referrer: "interruption_screen", original_log_id:)
end
def change_duplicate_logs_action_href(log, page_id, all_duplicates, original_log_id)
first_remaining_duplicate_id = all_duplicates.map(&:id).reject { |id| id == log.id }.first
send("#{log.model_name.param_key}_#{page_id}_path", log, referrer: params[:referrer] == "duplicate_logs_banner" ? "duplicate_logs_banner" : "duplicate_logs", first_remaining_duplicate_id:, original_log_id:, organisation_id: params[:organisation_id])
send("#{log.log_type}_#{page_id}_path", log, referrer: params[:referrer] == "duplicate_logs_banner" ? "duplicate_logs_banner" : "duplicate_logs", first_remaining_duplicate_id:, original_log_id:, organisation_id: params[:organisation_id])
end
def duplicates_for_user(user)

6
app/helpers/form_page_helper.rb

@ -1,6 +1,6 @@
module FormPageHelper
def action_href(log, page_id, referrer = "check_answers")
send("#{log.model_name.param_key}_#{page_id}_path", log, referrer:)
send("#{log.log_type}_#{page_id}_path", log, referrer:)
end
def returning_to_question_page?(page, referrer)
@ -12,11 +12,11 @@ module FormPageHelper
end
def duplicate_log_set_path(log, original_log_id)
send("#{log.class.name.underscore}_duplicate_logs_path", log, original_log_id:)
send("#{log.log_type}_duplicate_logs_path", log, original_log_id:)
end
def relevant_check_answers_path(log, subsection)
send("#{log.class.name.underscore}_#{subsection.id}_check_answers_path", log)
send("#{log.log_type}_#{subsection.id}_check_answers_path", log)
end
def submit_button_text(page, referrer)

2
app/helpers/guidance_helper.rb

@ -6,6 +6,6 @@ module GuidanceHelper
question = log.form.get_question(question_id, log)
return "" unless question.page.routed_to?(log, user)
"(#{govuk_link_to "Q#{question.question_number}", send("#{log.class.name.underscore}_#{question.page.id}_path", log)})".html_safe
"(#{govuk_link_to "Q#{question.question_number}", send("#{log.log_type}_#{question.page.id}_path", log)})".html_safe
end
end

4
app/helpers/tasklist_helper.rb

@ -78,9 +78,9 @@ private
def next_page_or_check_answers(subsection, log, current_user)
path = if subsection.is_started?(log)
"#{log.class.name.underscore}_#{subsection.id}_check_answers_path"
"#{log.log_type}_#{subsection.id}_check_answers_path"
else
"#{log.class.name.underscore}_#{next_question_page(subsection, log, current_user)}_path"
"#{log.log_type}_#{next_question_page(subsection, log, current_user)}_path"
end
send(path, log)

2
app/models/form.rb

@ -135,7 +135,7 @@ class Form
end
def cancel_path(page, log)
"#{log.class.name.underscore}_#{page.subsection.id}_check_answers_path"
"#{log.log_type}_#{page.subsection.id}_check_answers_path"
end
def unresolved_log_path

2
app/models/form/lettings/pages/address_matcher.rb

@ -24,6 +24,6 @@ class Form::Lettings::Pages::AddressMatcher < ::Form::Page
def skip_href(log = nil)
return unless log
"/#{log.model_name.param_key.dasherize}s/#{log.id}/property-unit-type"
"/#{log.log_type.dasherize}s/#{log.id}/property-unit-type"
end
end

2
app/models/form/sales/pages/address_matcher.rb

@ -24,6 +24,6 @@ class Form::Sales::Pages::AddressMatcher < ::Form::Page
def skip_href(log = nil)
return unless log
"/#{log.model_name.param_key.dasherize}s/#{log.id}/property-number-of-bedrooms"
"/#{log.log_type.dasherize}s/#{log.id}/property-number-of-bedrooms"
end
end

4
app/models/lettings_log.rb

@ -735,6 +735,10 @@ class LettingsLog < Log
scheme_locations_count > 19
end
def log_type
"lettings_log"
end
private
def reset_invalid_unresolved_log_fields!

4
app/models/sales_log.rb

@ -538,4 +538,8 @@ class SalesLog < Log
def is_firststair?
firststair == 1
end
def log_type
"sales_log"
end
end

2
app/views/check_errors/confirm_clear_all_answers.html.erb

@ -10,7 +10,7 @@
<p class="govuk-body">You've selected <%= @questions_to_clear.count %> answers to clear</p>
<%= 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| %>
<%= form_with model: @log, url: send("#{@log.log_type}_#{@page.id}_path", @log), method: "post", local: true do |f| %>
<% @related_question_ids.each do |id| %>
<%= f.hidden_field id, value: @log[id] %>

2
app/views/check_errors/confirm_clear_answer.html.erb

@ -9,7 +9,7 @@
</h1>
<%= 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| %>
<%= form_with model: @log, url: send("#{@log.log_type}_#{@page.id}_path", @log), method: "post", local: true do |f| %>
<% @related_question_ids.each do |id| %>
<%= f.hidden_field id, value: @log[id] %>

25
app/views/components/_date_picker.html.erb

@ -0,0 +1,25 @@
<div class="moj-datepicker" data-module="moj-date-picker">
<% question_has_errors = resource.errors[question_id].any? %>
<div class="govuk-form-group<%= " govuk-form-group--error" if question_has_errors %>">
<% if legend.present? %>
<legend class="govuk-fieldset__legend govuk-fieldset__legend--<%= legend[:size] %>">
<h1 class="govuk-fieldset__heading">
<span class="govuk-caption-l">
<%= legend[:caption][:text] if legend[:caption].present? %>
</span>
<%= legend[:text] %>
</h1>
</legend>
<% end %>
<div class="govuk-hint" id="<%= [resource_type.dasherize, question_id.to_s.dasherize, "hint"].join("-") %>">
<%= hint %>
</div>
<% if question_has_errors %>
<p class="govuk-error-message" id="<%= [resource_type.dasherize, question_id.to_s.dasherize, "error"].join("-") %>">
<span class="govuk-visually-hidden">Error:</span> <%= resource.errors[question_id].first %>
</p>
<% end %>
<%= f.text_field question_id.to_sym, class: "govuk-input moj-js-datepicker-input#{' govuk-input--error' if question_has_errors}", id: [resource_type, question_id].join("_"), aria: { describedby: "#{[resource_type, question_id].join('_')}-hint#{"#{[resource_type, question_id].join('_')} -error" if question_has_errors}" }, autocomplete: "off", value: resource[question_id]&.strftime("%d/%m/%Y") %>
</div>
</div>

2
app/views/duplicate_logs/_duplicate_log.html.erb

@ -4,7 +4,7 @@
<div class="govuk-grid-column-one-third">
<header class="app-log-summary__header">
<h2 class="app-log-summary__title">
<%= govuk_link_to "Log #{log.id}", send("#{log.class.name.underscore}_path", log) %>
<%= govuk_link_to "Log #{log.id}", send("#{log.log_type}_path", log) %>
</h2>
</header>
</div>

18
app/views/form/_date_question.html.erb

@ -1,12 +1,14 @@
<%= render partial: "form/guidance/#{question.top_guidance_partial}" if question.top_guidance? %>
<%= render partial: "components/date_picker", locals:
{
resource: @log,
question_id: question.id,
legend: { text: legend(question, page_header, conditional)[:text], size: "l", caption: caption(caption_text, page_header, conditional) },
resource_type: @log.log_type,
hint: (question.hint_text.blank? ? "" : (question.hint_text.html_safe + "</br></br>".html_safe)) + "For example, #{date_mid_collection_year_formatted(@log.startdate).tr(' ', '/')}",
f:,
} %>
<%= f.govuk_date_field question.id.to_sym,
caption: caption(caption_text, page_header, conditional),
legend: legend(question, page_header, conditional),
hint: { text: (question.hint_text.blank? ? "" : (question.hint_text.html_safe + "</br></br>".html_safe)) + "For example, #{date_mid_collection_year_formatted(@log.startdate)}" },
width: 20,
**stimulus_html_attributes(question) do %>
<%= govuk_inset_text(text: question.unresolved_hint_text) if question.unresolved_hint_text.present? && @log.unresolved %>
<% end %>
<%= govuk_inset_text(text: question.unresolved_hint_text) if question.unresolved_hint_text.present? && @log.unresolved %>
<%= render partial: "form/guidance/#{question.bottom_guidance_partial}" if question.bottom_guidance? %>

4
app/views/form/check_errors.html.erb

@ -1,7 +1,7 @@
<div class="govuk-grid-row">
<div class="govuk-grid-column-three-quarters-from-desktop">
<%= form_with model: @log, url: send("#{@log.model_name.param_key}_confirm_clear_answer_path", @log), method: "post", local: true do |f| %>
<%= form_with model: @log, url: send("#{@log.log_type}_confirm_clear_answer_path", @log), method: "post", local: true do |f| %>
<% remove_duplicate_page_errors(@log) %>
<%= f.govuk_error_summary %>
<%= f.hidden_field :page_id, value: @page.id %>
@ -62,6 +62,6 @@
</div>
<% end %>
<%= govuk_button_link_to "Confirm and continue", @original_page_id ? send("#{@log.model_name.param_key}_#{@original_page_id}_path", @log) : send("#{@log.model_name.param_key}_#{@page.id}_path", @log) %>
<%= govuk_button_link_to "Confirm and continue", @original_page_id ? send("#{@log.log_type}_#{@original_page_id}_path", @log) : send("#{@log.log_type}_#{@page.id}_path", @log) %>
</div>
</div>

12
app/views/locations/availability.erb

@ -12,11 +12,13 @@
<%= f.govuk_error_summary %>
<%= render partial: "organisations/headings", locals: { main: I18n.t("questions.location.startdate"), sub: "Add a location to #{@scheme.service_name}" } %>
<%= f.govuk_date_field :startdate,
hint: { text: I18n.t("hints.location.startdate") },
legend: nil,
width: 20 %>
<%= render partial: "components/date_picker", locals: {
resource: @location,
question_id: "startdate",
legend: nil,
resource_type: "location",
hint: I18n.t("hints.location.startdate"),
f: } %>
<div class="govuk-button-group">
<% if params[:referrer] == "check_answers" %>

15
app/views/locations/toggle_active.html.erb

@ -25,11 +25,16 @@
"other",
label: { text: "For tenancies starting after a certain date" },
**basic_conditional_html_attributes({ "deactivation_date" => %w[other] }, "location") do %>
<%= f.govuk_date_field date_question(action),
legend: { text: "Date", size: "m" },
hint: { text: "For example, 27 3 2022" },
width: 20 %>
<% end %>
<%= render partial: "components/date_picker", locals: {
resource: @location,
question_id: date_question(action),
legend: { text: "Date", size: "m" },
resource_type: "location",
hint: "For example, 27/3/2024",
f:,
} %>
<% end %>
<% end %>
<%= f.govuk_submit "Continue" %>

4
app/views/logs/delete_duplicates.html.erb

@ -19,12 +19,12 @@
<div class="govuk-button-group">
<%= govuk_button_to @duplicate_logs.count == 1 ? "Delete this log" : "Delete these logs",
send("delete_logs_#{@log.class.name.underscore}s_path"),
send("delete_logs_#{@log.log_type}s_path"),
method: "delete",
params: { ids: @duplicate_logs.map(&:id), original_log_id: @original_log.id, remaining_log_id: @log.id, referrer: params[:referrer], organisation_id: params[:organisation_id] } %>
<%= govuk_button_link_to(
"Cancel",
send("#{@log.class.name.underscore}_duplicate_logs_path", @original_log, original_log_id: @original_log.id, referrer: params[:referrer], organisation_id: params[:organisation_id]),
send("#{@log.log_type}_duplicate_logs_path", @original_log, original_log_id: @original_log.id, referrer: params[:referrer], organisation_id: params[:organisation_id]),
secondary: true,
) %>
</div>

14
app/views/merge_requests/merge_date.html.erb

@ -11,11 +11,15 @@
<h2 class="govuk-heading-l">What is the merge date?</h2>
<p class="govuk-hint">
Enter the official merge date. Log and organisation page data will show the new organisation name from this date. <br><br>
For example, <%= date_mid_collection_year_formatted(Time.zone.now) %></p>
<%= f.govuk_date_field :merge_date,
legend: { hidden: true },
width: 20 do %>
<% end %>
For example, <%= date_mid_collection_year_formatted(Time.zone.now).tr(" ", "/") %></p>
<%= render partial: "components/date_picker", locals: {
resource: @merge_request,
question_id: "merge_date",
legend: nil,
resource_type: "merge_request",
hint: "",
f:,
} %>
<%= f.hidden_field :page, value: "merge_date" %>
<div class="govuk-button-group">
<%= f.govuk_submit submit_merge_request_button_text(request.query_parameters["referrer"]) %>

12
app/views/schemes/toggle_active.html.erb

@ -25,10 +25,14 @@
"other",
label: { text: "For tenancies starting after a certain date" },
**basic_conditional_html_attributes({ "deactivation_date" => %w[other] }, "scheme") do %>
<%= f.govuk_date_field date_question(action),
legend: { text: "Date", size: "m" },
hint: { text: "For example, 27 3 2025" },
width: 20 %>
<%= render partial: "components/date_picker", locals: {
resource: @scheme,
question_id: date_question(action),
legend: { text: "Date", size: "m" },
resource_type: "scheme",
hint: "For example, 27/3/2025",
f:,
} %>
<% end %>
<% end %>
<%= f.govuk_submit "Continue" %>

1
config/initializers/assets.rb

@ -5,5 +5,6 @@ Rails.application.config.assets.version = "1.0"
# Add additional assets to the asset load path.
Rails.application.config.assets.paths << Rails.root.join("node_modules/@fortawesome/fontawesome-free/webfonts")
Rails.application.config.assets.paths << Rails.root.join("/node_modules/@ministryofjustice/frontend/moj/assets")
Rails.application.config.assets.precompile += %w[rails_admin/rails_admin.css rails_admin/rails_admin.js]

2
config/locales/en.yml

@ -413,7 +413,7 @@ en:
name: "This is how you refer to this location within your organisation."
units: "A unit is the space being let. For example, the property might be a block of flats and the unit would be the specific flat being let. A unit can also be a bedroom in a shared house or flat. Do not include spaces used for staff."
toggle_active: "If the date is before %{date}, select ‘From the start of the open collection period’ because the previous period has now closed."
startdate: "For example, 27 3 2021."
startdate: "For example, 27/3/2024."
scheme:
toggle_active: "If the date is before %{date}, select ‘From the start of the open collection period’ because the previous period has now closed."
bulk_upload:

2
package.json

@ -9,6 +9,7 @@
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@hotwired/stimulus": "^3.0.0",
"@ministryofjustice/frontend": "^3.3.0",
"@stimulus/polyfills": "^2.0.0",
"@webcomponents/webcomponentsjs": "^2.6.0",
"@x-govuk/govuk-prototype-components": "^3.0.9",
@ -23,6 +24,7 @@
"govuk-frontend": "5.7.1",
"html5shiv": "^3.7.3",
"intersection-observer": "^0.12.0",
"jquery": "^3.7.1",
"mini-css-extract-plugin": "^2.6.0",
"rails_admin": "3.3.0",
"regenerator-runtime": "^0.13.9",

28
spec/features/form/page_routing_spec.rb

@ -95,50 +95,36 @@ RSpec.describe "Form Page Routing" do
it "does not reset the displayed date if it's an invalid date" do
lettings_log.update!(startdate: "2021/10/13")
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "32")
fill_in("lettings_log[startdate(3i)]", with: "0")
fill_in("lettings_log[startdate]", with: "0/32/202")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate(3i)]").value).to eq("13")
expect(find_field("lettings_log[startdate(2i)]").value).to eq("10")
expect(find_field("lettings_log[startdate(1i)]").value).to eq("2021")
expect(find_field("lettings_log[startdate]").value).to eq("13/10/2021")
end
it "displays the entered date if it's in a valid format" do
lettings_log.update!(startdate: "2021/10/13")
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "12")
fill_in("lettings_log[startdate(3i)]", with: "1")
fill_in("lettings_log[startdate]", with: "1/12/202")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate(3i)]").value).to eq("1")
expect(find_field("lettings_log[startdate(2i)]").value).to eq("12")
expect(find_field("lettings_log[startdate(1i)]").value).to eq("202")
expect(find_field("lettings_log[startdate]").value).to eq("01/12/0202")
end
it "does not reset the displayed date if it's empty" do
lettings_log.update!(startdate: nil)
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "32")
fill_in("lettings_log[startdate(3i)]", with: "0")
fill_in("lettings_log[startdate]", with: "0/32/202")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate(3i)]").value).to eq(nil)
expect(find_field("lettings_log[startdate(2i)]").value).to eq(nil)
expect(find_field("lettings_log[startdate(1i)]").value).to eq(nil)
expect(find_field("lettings_log[startdate]").value).to eq(nil)
end
it "does not show see all related answers link if only 1 field has an error" do
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "32")
fill_in("lettings_log[startdate(3i)]", with: "0")
fill_in("lettings_log[startdate]", with: "0/32/202")
click_button("Save and continue")
expect(page).not_to have_link("See all related answers")

4
spec/features/form/validations_spec.rb

@ -63,9 +63,7 @@ RSpec.describe "validations" do
describe "date validation", js: true do
def fill_in_date(lettings_log_id, question, day, month, year, path)
visit("/lettings-logs/#{lettings_log_id}/#{path}")
fill_in("lettings_log[#{question}(1i)]", with: year)
fill_in("lettings_log[#{question}(2i)]", with: month)
fill_in("lettings_log[#{question}(3i)]", with: day)
fill_in("lettings_log[#{question}]", with: [day, month, year].join("/"))
end
it "does not allow out of range dates to be submitted" do

5
spec/features/sales_log_spec.rb

@ -34,9 +34,8 @@ RSpec.describe "Sales Log Features" do
it "includes the purchaser code and sale completion date questions" do
click_button "Create a new sales log"
click_link "Set up this sales log"
fill_in("sales_log[saledate(1i)]", with: Time.zone.today.year)
fill_in("sales_log[saledate(2i)]", with: Time.zone.today.month)
fill_in("sales_log[saledate(3i)]", with: Time.zone.today.day)
date = Time.zone.today.strftime("%d/%m/%Y")
fill_in("sales_log[saledate]", with: date)
click_button "Save and continue"
fill_in "sales_log[purchid]", with: "PC123"
click_button "Save and continue"

8
spec/features/schemes_helpers.rb

@ -74,9 +74,7 @@ module SchemesHelpers
click_button "Save and continue"
choose "location-mobility-type-none-field"
click_button "Save and continue"
fill_in "Day", with: 2
fill_in "Month", with: 5
fill_in "Year", with: 2023
fill_in "location_startdate", with: "2/5/2023"
click_button "Save and continue"
end
@ -95,9 +93,7 @@ module SchemesHelpers
click_button "Save and continue"
choose "location-mobility-type-none-field"
click_button "Save and continue"
fill_in "Day", with: 2
fill_in "Month", with: 5
fill_in "Year", with: 2023
fill_in "location_startdate", with: "2/5/2023"
click_button "Save and continue"
end

8
spec/features/schemes_spec.rb

@ -368,9 +368,7 @@ RSpec.describe "Schemes scheme Features" do
click_button "Save and continue"
choose "location-mobility-type-none-field"
click_button "Save and continue"
fill_in "Day", with: 2
fill_in "Month", with: 2
fill_in "Year", with: 2022
fill_in "location_startdate", with: "2/2/2022"
click_button "Save and continue"
end
@ -989,9 +987,7 @@ RSpec.describe "Schemes scheme Features" do
click_button "Save and continue"
choose "location-mobility-type-none-field"
click_button "Save and continue"
fill_in "Day", with: 2
fill_in "Month", with: 2
fill_in "Year", with: 2022
fill_in "location_startdate", with: "2/2/2022"
click_button "Save and continue"
end

32
spec/requests/form_controller_spec.rb

@ -329,9 +329,7 @@ RSpec.describe FormController, type: :request do
id: sales_log.id,
sales_log: {
page: "completion_date",
"saledate(3i)" => 30,
"saledate(2i)" => 6,
"saledate(1i)" => 2023,
"saledate" => "30/6/2023",
},
}
end
@ -609,9 +607,7 @@ RSpec.describe FormController, type: :request do
id: lettings_log.id,
lettings_log: {
page: page_id,
"startdate(3i)" => 31,
"startdate(2i)" => 6,
"startdate(1i)" => 2022,
"startdate" => "31/6/2022",
},
}
end
@ -635,9 +631,7 @@ RSpec.describe FormController, type: :request do
id: lettings_log.id,
lettings_log: {
page: page_id,
"startdate(3i)" => 1,
"startdate(2i)" => 1,
"startdate(1i)" => 1,
"startdate" => "1/1/1",
},
}
end
@ -658,9 +652,7 @@ RSpec.describe FormController, type: :request do
id: sales_log.id,
sales_log: {
page: page_id,
"saledate(3i)" => 1,
"saledate(2i)" => 1,
"saledate(1i)" => 1,
"saledate" => "1/1/1",
},
}
end
@ -687,9 +679,7 @@ RSpec.describe FormController, type: :request do
id: lettings_log.id,
lettings_log: {
page: page_id,
"startdate(3i)" => 1,
"startdate(2i)" => 1,
"startdate(1i)" => 1,
"startdate" => "1/1/1",
},
}
end
@ -708,9 +698,7 @@ RSpec.describe FormController, type: :request do
id: sales_log.id,
sales_log: {
page: page_id,
"saledate(3i)" => 1,
"saledate(2i)" => 1,
"saledate(1i)" => 1,
"saledate" => "1/1/1",
},
}
end
@ -1326,9 +1314,7 @@ RSpec.describe FormController, type: :request do
id: sales_log.id,
sales_log: {
page: "completion_date",
"saledate(3i)" => 30,
"saledate(2i)" => 6,
"saledate(1i)" => 2023,
"saledate" => "30/6/2023",
},
}
end
@ -1364,9 +1350,7 @@ RSpec.describe FormController, type: :request do
id: sales_log.id,
sales_log: {
page: "completion_date",
"saledate(3i)" => 30,
"saledate(2i)" => 6,
"saledate(1i)" => 2024,
"saledate" => "30/06/2024",
},
}
end

46
spec/requests/locations_controller_spec.rb

@ -1151,7 +1151,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when startdate is submitted" do
let(:params) { { location: { "startdate(1i)": "2022", "startdate(2i)": "1", "startdate(3i)": "2" } } }
let(:params) { { location: { "startdate": "2/1/2022" } } }
before do
patch "/schemes/#{scheme.id}/locations/#{location.id}/availability", params:
@ -1168,7 +1168,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when startdate is submitted with leading zeroes" do
let(:params) { { location: { "startdate(1i)": "2022", "startdate(2i)": "01", "startdate(3i)": "02" } } }
let(:params) { { location: { "startdate": "02/01/2022" } } }
before do
patch "/schemes/#{scheme.id}/locations/#{location.id}/availability", params:
@ -1185,7 +1185,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when startdate is missing" do
let(:params) { { location: { "startdate(1i)": "", "startdate(2i)": "", "startdate(3i)": "" } } }
let(:params) { { location: { "startdate": "" } } }
before do
patch "/schemes/#{scheme.id}/locations/#{location.id}/availability", params:
@ -1225,7 +1225,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when startdate is submitted" do
let(:params) { { location: { "startdate(1i)": "2022", "startdate(2i)": "1", "startdate(3i)": "2" } } }
let(:params) { { location: { "startdate": "2/1/2022" } } }
before do
patch "/schemes/#{scheme.id}/locations/#{location.id}/availability", params:
@ -1242,7 +1242,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when startdate is submitted with leading zeroes" do
let(:params) { { location: { "startdate(1i)": "2022", "startdate(2i)": "01", "startdate(3i)": "02" } } }
let(:params) { { location: { "startdate": "02/01/2022" } } }
before do
patch "/schemes/#{scheme.id}/locations/#{location.id}/availability", params:
@ -1259,7 +1259,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when startdate is missing" do
let(:params) { { location: { "startdate(1i)": "", "startdate(2i)": "", "startdate(3i)": "" } } }
let(:params) { { location: { "startdate": "" } } }
before do
patch "/schemes/#{scheme.id}/locations/#{location.id}/availability", params:
@ -1548,7 +1548,7 @@ RSpec.describe LocationsController, type: :request do
end
context "with other date" do
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "10", "deactivation_date(2i)": "10", "deactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "10/10/2022" } } }
context "and affected logs" do
it "redirects to the confirmation page" do
@ -1708,7 +1708,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when invalid date is entered" do
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "10", "deactivation_date(2i)": "44", "deactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "10/44/2022" } } }
it "displays the new page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -1717,7 +1717,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the date entered is before the beginning of current collection window" do
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "10", "deactivation_date(2i)": "4", "deactivation_date(1i)": "2020" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "10/4/2020" } } }
it "displays the new page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -1726,7 +1726,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the day is not entered" do
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "", "deactivation_date(2i)": "2", "deactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "/2/2022" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -1735,7 +1735,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the month is not entered" do
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "2", "deactivation_date(2i)": "", "deactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "2//2022" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -1744,7 +1744,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the year is not entered" do
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "2", "deactivation_date(2i)": "2", "deactivation_date(1i)": "" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "2/2/" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -1754,7 +1754,7 @@ RSpec.describe LocationsController, type: :request do
context "when deactivation date is during a deactivated period" do
let(:deactivation_date) { Time.zone.local(2022, 10, 10) }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "8", "deactivation_date(2i)": "9", "deactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "8/9/2022" } } }
let(:add_deactivations) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 10, 12), location:) }
it "displays page with an error message" do
@ -1765,7 +1765,7 @@ RSpec.describe LocationsController, type: :request do
context "when there is an earlier open deactivation" do
let(:deactivation_date) { Time.zone.local(2023, 10, 10) }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "8", "deactivation_date(2i)": "9", "deactivation_date(1i)": "2024" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "8/9/2024" } } }
let(:add_deactivations) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2024, 6, 5), reactivation_date: nil, location:) }
it "redirects to the location page and updates the existing deactivation period" do
@ -1780,7 +1780,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when there is a later open deactivation" do
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "8", "deactivation_date(2i)": "9", "deactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "8/9/2022" } } }
let(:add_deactivations) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2024, 6, 5), reactivation_date: nil, location:) }
it "redirects to the confirmation page" do
@ -2078,7 +2078,7 @@ RSpec.describe LocationsController, type: :request do
end
context "with other date" do
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "10", "reactivation_date(2i)": "9", "reactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "10/9/2022" } } }
it "redirects to the location page and displays a success banner" do
expect(response).to redirect_to("/schemes/#{scheme.id}/locations/#{location.id}")
@ -2096,7 +2096,7 @@ RSpec.describe LocationsController, type: :request do
end
context "with other future date" do
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "14", "reactivation_date(2i)": "12", "reactivation_date(1i)": "2023" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "14/12/2023" } } }
it "redirects to the location page and displays a success banner" do
expect(response).to redirect_to("/schemes/#{scheme.id}/locations/#{location.id}")
@ -2116,7 +2116,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when invalid date is entered" do
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "10", "reactivation_date(2i)": "44", "reactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "10/44/2022" } } }
it "displays the new page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2125,7 +2125,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the date is entered is before the beginning of current collection window" do
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "10", "reactivation_date(2i)": "4", "reactivation_date(1i)": "2020" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "10/4/2020" } } }
it "displays the new page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2134,7 +2134,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the day is not entered" do
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "", "reactivation_date(2i)": "2", "reactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "/2/2022" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2143,7 +2143,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the month is not entered" do
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "2", "reactivation_date(2i)": "", "reactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "2//2022" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2152,7 +2152,7 @@ RSpec.describe LocationsController, type: :request do
end
context "when the year is not entered" do
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "2", "reactivation_date(2i)": "2", "reactivation_date(1i)": "" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "2/2/" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2162,7 +2162,7 @@ RSpec.describe LocationsController, type: :request do
context "when the reactivation date is before deactivation date" do
let(:deactivation_date) { Time.zone.local(2022, 10, 10) }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date(3i)": "8", "reactivation_date(2i)": "9", "reactivation_date(1i)": "2022" } } }
let(:params) { { location_deactivation_period: { reactivation_date_type: "other", "reactivation_date": "8/9/2022" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)

8
spec/requests/merge_requests_controller_spec.rb

@ -354,7 +354,7 @@ RSpec.describe MergeRequestsController, type: :request do
context "when not answering the question" do
let(:merge_request) { MergeRequest.create!(requesting_organisation: organisation, absorbing_organisation: other_organisation) }
let(:params) do
{ merge_request: { page: "merge_date" } }
{ merge_request: { merge_date: "", page: "merge_date" } }
end
let(:request) do
patch "/merge-request/#{merge_request.id}", headers:, params:
@ -375,7 +375,7 @@ RSpec.describe MergeRequestsController, type: :request do
context "when merge date set to an invalid date" do
let(:merge_request) { MergeRequest.create!(requesting_organisation: organisation) }
let(:params) do
{ merge_request: { page: "merge_date", "merge_date(3i)": "10", "merge_date(2i)": "44", "merge_date(1i)": "2022" } }
{ merge_request: { page: "merge_date", "merge_date": "10/44/2022" } }
end
let(:request) do
@ -393,7 +393,7 @@ RSpec.describe MergeRequestsController, type: :request do
context "when merge date set to a valid date" do
let(:merge_request) { MergeRequest.create!(requesting_organisation: organisation) }
let(:params) do
{ merge_request: { page: "merge_date", "merge_date(3i)": "10", "merge_date(2i)": "4", "merge_date(1i)": "2022" } }
{ merge_request: { page: "merge_date", "merge_date": "10/4/2022" } }
end
let(:request) do
@ -416,7 +416,7 @@ RSpec.describe MergeRequestsController, type: :request do
context "when merge date set to a date more than 1 year in the future" do
let(:merge_request) { MergeRequest.create!(requesting_organisation: organisation) }
let(:params) do
{ merge_request: { page: "merge_date", "merge_date(3i)": (Time.zone.now.day + 1).to_s, "merge_date(2i)": Time.zone.now.month.to_s, "merge_date(1i)": (Time.zone.now.year + 1).to_s } }
{ merge_request: { page: "merge_date", "merge_date": [(Time.zone.now.day + 1).to_s, Time.zone.now.month.to_s, (Time.zone.now.year + 1).to_s].join("/") } }
end
let(:request) do

16
spec/requests/schemes_controller_spec.rb

@ -2749,7 +2749,7 @@ RSpec.describe SchemesController, type: :request do
end
context "with other date" do
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "10", "deactivation_date(2i)": "10", "deactivation_date(1i)": "2022" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "10/10/2022" } } }
context "and affected logs" do
it "redirects to the confirmation page" do
@ -2901,7 +2901,7 @@ RSpec.describe SchemesController, type: :request do
end
context "when invalid date is entered" do
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "10", "deactivation_date(2i)": "44", "deactivation_date(1i)": "2022" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "10/44/2022" } } }
it "displays the new page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2910,7 +2910,7 @@ RSpec.describe SchemesController, type: :request do
end
context "when the date is entered is before the beginning of current collection window" do
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "10", "deactivation_date(2i)": "4", "deactivation_date(1i)": "2020" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "10/4/2020" } } }
it "displays the new page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2919,7 +2919,7 @@ RSpec.describe SchemesController, type: :request do
end
context "when the day is not entered" do
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "", "deactivation_date(2i)": "2", "deactivation_date(1i)": "2022" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "/2/2022" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2928,7 +2928,7 @@ RSpec.describe SchemesController, type: :request do
end
context "when the month is not entered" do
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "2", "deactivation_date(2i)": "", "deactivation_date(1i)": "2022" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "2//2022" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2937,7 +2937,7 @@ RSpec.describe SchemesController, type: :request do
end
context "when the year is not entered" do
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "2", "deactivation_date(2i)": "2", "deactivation_date(1i)": "" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "2/2/" } } }
it "displays page with an error message" do
expect(response).to have_http_status(:unprocessable_content)
@ -2947,7 +2947,7 @@ RSpec.describe SchemesController, type: :request do
context "when there is an earlier open deactivation" do
let(:deactivation_date) { Time.zone.local(2022, 10, 10) }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "8", "deactivation_date(2i)": "9", "deactivation_date(1i)": "2023" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "8/9/2023" } } }
let(:add_deactivations) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2023, 6, 5), reactivation_date: nil, scheme:) }
before do
@ -2968,7 +2968,7 @@ RSpec.describe SchemesController, type: :request do
context "when there is a later open deactivation" do
let(:deactivation_date) { Time.zone.local(2022, 10, 10) }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date(3i)": "8", "deactivation_date(2i)": "9", "deactivation_date(1i)": "2022" } } }
let(:params) { { scheme_deactivation_period: { deactivation_date_type: "other", "deactivation_date": "8/9/2022" } } }
let(:add_deactivations) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2023, 6, 5), reactivation_date: nil, scheme:) }
it "redirects to the confirmation page" do

6
webpack.config.js

@ -41,7 +41,8 @@ module.exports = {
resolve: {
alias: {
'govuk-frontend-styles': path.resolve(__dirname, 'node_modules/govuk-frontend/dist/govuk/all.scss'),
'govuk-prototype-styles': path.resolve(__dirname, 'node_modules/@x-govuk/govuk-prototype-components/x-govuk/all.scss')
'govuk-prototype-styles': path.resolve(__dirname, 'node_modules/@x-govuk/govuk-prototype-components/x-govuk/all.scss'),
'moj-frontend': path.resolve(__dirname, 'node_modules/@ministryofjustice/frontend/moj/all.js')
},
modules: ['node_modules', 'node_modules/govuk-frontend/dist/govuk']
},
@ -62,7 +63,8 @@ module.exports = {
{ from: 'node_modules/govuk-frontend/dist/govuk/assets/fonts', to: 'fonts' },
{ from: 'node_modules/html5shiv/dist/html5shiv.min.js', to: 'vendor' },
{ from: 'app/frontend/vendor/outerHTML.js', to: 'vendor' },
{ from: 'app/frontend/vendor/polyfill-output-value.js', to: 'vendor' }
{ from: 'app/frontend/vendor/polyfill-output-value.js', to: 'vendor' },
{ from: 'node_modules/@ministryofjustice/frontend/moj/all.js', to: 'vendor' }
]
})
]

17
yarn.lock

@ -1109,6 +1109,14 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@ministryofjustice/frontend@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@ministryofjustice/frontend/-/frontend-3.3.0.tgz#45bb0359fa9a466a574d44e2a78121f5544c2eeb"
integrity sha512-kK1+XTI8KPgL2kA3ylTkXfXqA2cirENh1oxTYnvogt6W8vg5VexGSYjynRZ5EhRUAQh6uHPmOGyr+mYXmNwReQ==
dependencies:
govuk-frontend "^5.0.0"
moment "^2.27.0"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -2734,7 +2742,7 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
govuk-frontend@5.7.1:
govuk-frontend@5.7.1, govuk-frontend@^5.0.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-5.7.1.tgz#d4c561ebf8c0b76130f31df8c2e4d70d340cd63f"
integrity sha512-jF1cq5rn57kxZmJRprUZhTQ31zaBBK4b5AyeJaPX3Yhg22lk90Mx/dQLvOk/ycV3wM7e0y+s4IPvb2fFaPlCGg==
@ -3124,7 +3132,7 @@ jest-worker@^27.4.5:
dependencies:
jquery ">=1.8.0 <4.0.0"
"jquery@>=1.8.0 <4.0.0", jquery@^3.6.0:
"jquery@>=1.8.0 <4.0.0", jquery@^3.6.0, jquery@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de"
integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==
@ -3386,6 +3394,11 @@ minimist@^1.2.0, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
moment@^2.27.0:
version "2.30.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"

Loading…
Cancel
Save