Browse Source

CLDC-3116 Create homepage (#2113)

* feat: add blank homepage, update routing and tests

* feat: add welcome message and thoroughly test routing

* refactor: lint

* feat: update tests

* CLDC-3076: Make example dates consistent (#2107)

* CLDC-3076: Make example dates consistent

* Use example date even when some hint text provided already

* Temp remove some date restrictions

* Update to 2 line breaks

* Revert "Temp remove some date restrictions"

This reverts commit cd7f18f9f1.

* Fix lettings log accessor in date question (#2117)

* Fix lettings log accessor in date question

* Remove hardcoded date example from mrcdate question (#2118)

---------

Co-authored-by: Rachael Booth <Rachael.Booth@softwire.com>

* CLDC-3061 Add guidance page (#2121)

* Add guidance page

* Link to guidance from start page

* feat: test home/start paths explicitly

* CLDC-2253 Add collection resources (#2120)

* Update collection resources, add to homepage

* Add guidance link to an empty page

* Update headings

* Rebase fix

* Update title

* Update file names

* Add section break

* CLDC-2593 Add upcoming deadlines section (#2119)

* Add upcoming deadlines section

* Update the content to use the correct dates

* Update content

* lint

* typos

* CLDC-2252 Add homepage task section (#2115)

* feat: wip add lettings, sales and schemes sections with correct text, counts, links and colouring

* feat: add flex styling to match designs

* CLDC-3076: Make example dates consistent (#2107)

* CLDC-3076: Make example dates consistent

* Use example date even when some hint text provided already

* Temp remove some date restrictions

* Update to 2 line breaks

* Revert "Temp remove some date restrictions"

This reverts commit cd7f18f9f1.

* Fix lettings log accessor in date question (#2117)

* Fix lettings log accessor in date question

* Remove hardcoded date example from mrcdate question (#2118)

---------

Co-authored-by: Rachael Booth <Rachael.Booth@softwire.com>

* feat: update breakpoints for responsive layout changes

* lint: use hash lookup where possible

* lint: erblinting

* feat: improve formatting

* Reuse govuk grid

* Revert "Reuse govuk grid"

This reverts commit 8c71f5d9ed.

* feat: test home page data boxes

* refactor: lint

* refactor: lint

* feat: test link behaviour is correct in all user scenarios

* refactor: lint

* feat: update tests

* feat: combine task, resources, deadlines sections

---------

Co-authored-by: Rachael Booth <Rachael.Booth@softwire.com>
Co-authored-by: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com>
Co-authored-by: Kat <kosiak.katrina@gmail.com>

* CLDC-2255 Add homepage notifications (#2131)

* feat: add notification table

* feat: add notification banner, use unread gem for notification management

* feat: add notifications page and remove unread_notification.rb

* feat: add blank homepage, update routing and tests

* feat: add welcome message and thoroughly test routing

* refactor: lint

* feat: update tests

* CLDC-3061 Add guidance page (#2121)

* Add guidance page

* Link to guidance from start page

* feat: test home/start paths explicitly

* feat: add notification table

* feat: add notification banner, use unread gem for notification management

* feat: add notifications page and remove unread_notification.rb

* feat: default p tag around sanitized page content

* feat: add active scope

* feat: use newest active unread/unauthenticated notification and update start page

* feat: add tests of notification behaviour and routing and refactor

* refactor: lint

* feat: update Gemfile.lock

* feat: add timestamps to readmark table

* feat: update gemfile.lock

* refactor: lint

* feat: test notifications page doesn't show notifications and code simplification

* feat: move notification helper methods to notifications_helper.rb

---------

Co-authored-by: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com>

* feat: clear all no-status filters on in progress links

* CLDC-2590 Add about this service section (#2124)

* Add about core section

* Move about core to the correct spot on start page

* Update content

* Add some margins

---------

Co-authored-by: Rachael Booth <Rachael.Booth@softwire.com>
Co-authored-by: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com>
Co-authored-by: Kat <kosiak.katrina@gmail.com>
pull/2143/head
natdeanlewissoftwire 11 months ago committed by GitHub
parent
commit
5a1e5674ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Gemfile
  2. 3
      Gemfile.lock
  3. 2
      app/controllers/auth/sessions_controller.rb
  4. 19
      app/controllers/notifications_controller.rb
  5. 2
      app/controllers/start_controller.rb
  6. 66
      app/frontend/styles/_data_box.scss
  7. 2
      app/frontend/styles/_document-list.scss
  8. 4
      app/frontend/styles/_header.scss
  9. 7
      app/frontend/styles/_unread-notification.scss
  10. 6
      app/frontend/styles/application.scss
  11. 18
      app/helpers/application_helper.rb
  12. 20
      app/helpers/collection_time_helper.rb
  13. 71
      app/helpers/home_helper.rb
  14. 6
      app/helpers/navigation_items_helper.rb
  15. 17
      app/helpers/notifications_helper.rb
  16. 4
      app/models/form_handler.rb
  17. 14
      app/models/notification.rb
  18. 10
      app/models/user.rb
  19. 9
      app/views/home/_data_box.html.erb
  20. 35
      app/views/home/_upcoming_deadlines.html.erb
  21. 58
      app/views/home/index.html.erb
  22. 7
      app/views/layouts/_about_this_service.html.erb
  23. 115
      app/views/layouts/_collection_resources.html.erb
  24. 8
      app/views/layouts/application.html.erb
  25. 23
      app/views/notifications/_notification_banner.html.erb
  26. 17
      app/views/notifications/show.html.erb
  27. 4
      app/views/organisations/show.html.erb
  28. 68
      app/views/start/guidance.html.erb
  29. 9
      app/views/start/index.html.erb
  30. 5
      config/routes.rb
  31. 14
      db/migrate/20240108145545_create_notification.rb
  32. 25
      db/migrate/20240108152935_unread_migration.rb
  33. 24
      db/schema.rb
  34. 10
      spec/factories/notification.rb
  35. 276
      spec/features/home_page_spec.rb
  36. 41
      spec/features/notifications_page_spec.rb
  37. 29
      spec/features/start_page_spec.rb
  38. 2
      spec/features/test_spec.rb
  39. 5
      spec/features/user_spec.rb
  40. 30
      spec/helpers/collection_time_helper_spec.rb
  41. 95
      spec/helpers/navigation_items_helper_spec.rb
  42. 1
      spec/requests/auth/passwords_controller_spec.rb
  43. 1
      spec/requests/maintenance_controller_spec.rb
  44. 36
      spec/requests/organisations_controller_spec.rb
  45. 90
      spec/requests/start_controller_spec.rb
  46. 12
      spec/requests/users_controller_spec.rb
  47. 31
      spec/views/layouts/application_layout_spec.rb

1
Gemfile

@ -64,6 +64,7 @@ gem "auto_strip_attributes"
# Use sidekiq for background processing # Use sidekiq for background processing
gem "sidekiq" gem "sidekiq"
gem "sidekiq-cron" gem "sidekiq-cron"
gem "unread"
group :development, :test do group :development, :test do
# Check gems for known vulnerabilities # Check gems for known vulnerabilities

3
Gemfile.lock

@ -408,6 +408,8 @@ GEM
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
uk_postcode (2.1.8) uk_postcode (2.1.8)
unicode-display_width (2.4.2) unicode-display_width (2.4.2)
unread (0.13.0)
activerecord (>= 6.1)
view_component (3.9.0) view_component (3.9.0)
activesupport (>= 5.2.0, < 8.0) activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
@ -493,6 +495,7 @@ DEPENDENCIES
timecop (~> 0.9.4) timecop (~> 0.9.4)
tzinfo-data tzinfo-data
uk_postcode uk_postcode
unread
view_component (~> 3.9) view_component (~> 3.9)
web-console (>= 4.1.0) web-console (>= 4.1.0)
webmock webmock

2
app/controllers/auth/sessions_controller.rb

@ -24,7 +24,7 @@ private
if resource.need_two_factor_authentication?(request) if resource.need_two_factor_authentication?(request)
user_two_factor_authentication_path user_two_factor_authentication_path
else else
params.dig("user", "start").present? ? lettings_logs_path : super params.dig("user", "start").present? ? root_path : super
end end
end end
end end

19
app/controllers/notifications_controller.rb

@ -0,0 +1,19 @@
class NotificationsController < ApplicationController
def dismiss
if current_user.blank?
redirect_to root_path
else
current_user.newest_active_unread_notification.mark_as_read! for: current_user
redirect_back(fallback_location: root_path)
end
end
def show
@notification = current_user&.newest_active_unread_notification || Notification.newest_active_unauthenticated_notification
if @notification&.page_content
render "show"
else
redirect_back(fallback_location: root_path)
end
end
end

2
app/controllers/start_controller.rb

@ -1,7 +1,7 @@
class StartController < ApplicationController class StartController < ApplicationController
def index def index
if current_user if current_user
redirect_to(lettings_logs_path) render "home/index"
end end
end end

66
app/frontend/styles/_data_box.scss

@ -0,0 +1,66 @@
.app-data-box-group {
@include govuk-font($size: 19);
font-weight: bold;
white-space: nowrap;
}
@media (min-width: 54.0625em) {
.app-data-box-group-one-third {
display: flex;
justify-content: space-between;
column-gap: govuk-spacing(4);
width: 100%;
min-width: 733.33px;
}
}
@media (min-width: 54.0625em) {
.app-data-box-one-third {
width: 33.3333%;
float: left;
}
}
@media (min-width: 54.0625em) {
.app-data-box__underline {
min-width: 733.33px;
}
}
@media (min-width: 54.0625em) {
.app-data-box-group-one-half {
display: flex;
justify-content: space-between;
column-gap: govuk-spacing(4);
width: 100%;
min-width: 733.33px;
}
}
@media (min-width: 54.0625em) {
.app-data-box-one-half {
width: 50%;
float: left;
}
}
@media (min-width: 54.0625em) {
.app-data-box-one-half__underline {
min-width: 733.33px;
}
}
.app-data-box__upper {
@include govuk-responsive-margin(2, "bottom");
@include govuk-responsive-padding(4);
background-color: govuk-colour("light-grey");
color: govuk-colour("blue");
}
.app-data-box__lower {
@include govuk-responsive-margin(4, "bottom");
@include govuk-responsive-padding(4);
background-color: govuk-colour("blue");
}
.app-data-box__count {
font-size: 48px;
color: govuk-colour("blue");
}

2
app/frontend/styles/_document-list.scss

@ -12,7 +12,7 @@
} }
.app-document-list__item-title { .app-document-list__item-title {
@include govuk-font($size: 16, $weight: "bold"); @include govuk-font($size: 16);
margin: 0 0 govuk-spacing(1); margin: 0 0 govuk-spacing(1);
} }

4
app/frontend/styles/_header.scss

@ -26,3 +26,7 @@
.app-header--orange .govuk-header__container { .app-header--orange .govuk-header__container {
border-bottom-color: govuk-colour("orange"); border-bottom-color: govuk-colour("orange");
} }
.app-header__no-border-bottom {
border-bottom: 0;
}

7
app/frontend/styles/_unread-notification.scss

@ -0,0 +1,7 @@
.app-unread-notification {
background-color: govuk-colour("blue");
}
.app-unread-notification p {
color: govuk-colour("white");
}

6
app/frontend/styles/application.scss

@ -25,7 +25,10 @@ $govuk-breakpoints: (
@import "accessible-autocomplete"; @import "accessible-autocomplete";
@import "button"; @import "button";
@import "card"; @import "card";
@import "data_box";
@import "delete-logs-table";
@import "document-list"; @import "document-list";
@import "errors";
@import "feedback"; @import "feedback";
@import "filter"; @import "filter";
@import "filter-layout"; @import "filter-layout";
@ -43,8 +46,7 @@ $govuk-breakpoints: (
@import "primary-navigation"; @import "primary-navigation";
@import "search"; @import "search";
@import "sub-navigation"; @import "sub-navigation";
@import "errors"; @import "unread-notification";
@import "delete-logs-table";
// App utilities // App utilities
.app-\!-colour-muted { .app-\!-colour-muted {

18
app/helpers/application_helper.rb

@ -10,21 +10,27 @@ module ApplicationHelper
end end
def govuk_header_classes(current_user) def govuk_header_classes(current_user)
if current_user && current_user.support? if current_user&.support?
"app-header app-header--orange" "app-header app-header--orange"
elsif ((current_user.blank? && Notification.active_unauthenticated_notifications.present?) || current_user&.active_unread_notifications.present?) && !current_page?(notifications_path)
"app-header app-header__no-border-bottom"
else else
"app-header" "app-header"
end end
end end
def govuk_phase_banner_tag(current_user) def govuk_phase_banner_tag(current_user)
if current_user && current_user.support? if current_user&.support?
{ colour: "orange", text: "Support beta" } { colour: "orange", text: "Support beta" }
else else
{ text: "Beta" } { text: "Beta" }
end end
end end
def notifications_to_display?
!current_page?(notifications_path) && (authenticated_user_has_notifications? || unauthenticated_user_has_notifications?)
end
private private
def paginated_title(title, pagy) def paginated_title(title, pagy)
@ -33,4 +39,12 @@ private
title + " (page #{pagy.page} of #{pagy.pages})" title + " (page #{pagy.page} of #{pagy.pages})"
end end
def authenticated_user_has_notifications?
current_user&.active_unread_notifications.present?
end
def unauthenticated_user_has_notifications?
current_user.blank? && Notification.active_unauthenticated_notifications.present?
end
end end

20
app/helpers/collection_time_helper.rb

@ -45,4 +45,24 @@ module CollectionTimeHelper
def previous_collection_start_date def previous_collection_start_date
current_collection_start_date - 1.year current_collection_start_date - 1.year
end end
def quarter_for_date(date: Time.zone.now)
quarters = [
{ quarter: "Q3", cutoff_date: Time.zone.local(2024, 1, 12), start_date: Time.zone.local(2023, 10, 1), end_date: Time.zone.local(2023, 12, 31) },
{ quarter: "Q1", cutoff_date: Time.zone.local(2024, 7, 12), start_date: Time.zone.local(2024, 4, 1), end_date: Time.zone.local(2024, 6, 30) },
{ quarter: "Q2", cutoff_date: Time.zone.local(2024, 10, 11), start_date: Time.zone.local(2024, 7, 1), end_date: Time.zone.local(2024, 9, 30) },
{ quarter: "Q3", cutoff_date: Time.zone.local(2025, 1, 10), start_date: Time.zone.local(2024, 10, 1), end_date: Time.zone.local(2024, 12, 31) },
]
quarter = quarters.find { |q| date.between?(q[:start_date], q[:cutoff_date] + 1.day) }
return unless quarter
OpenStruct.new(
quarter: quarter[:quarter],
cutoff_date: quarter[:cutoff_date],
quarter_start_date: quarter[:start_date],
quarter_end_date: quarter[:end_date],
)
end
end end

71
app/helpers/home_helper.rb

@ -0,0 +1,71 @@
module HomeHelper
def data_count(user, type)
if user.data_provider?
case type
when "lettings" then user.lettings_logs.in_progress.where(created_by: user).count
when "sales" then user.sales_logs.in_progress.where(created_by: user).count
when "misc" then user.lettings_logs.completed.where(created_by: user).count
end
else
case type
when "lettings" then user.lettings_logs.in_progress.count
when "sales" then user.sales_logs.in_progress.count
when "schemes" then user.schemes.incomplete.count
end
end
end
def heading_for_user_role(user)
ROLE_HEADINGS[user.role]
end
def data_subheading(user, type)
case type
when "schemes"
"Incomplete schemes"
when "misc"
"Your completed lettings"
else
"#{user.role == 'data_provider' ? :"Your " : nil}#{type} in progress".capitalize
end
end
def data_path(user, type)
if user.data_provider?
case type
when "lettings" then lettings_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all")
when "sales" then sales_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all")
when "misc" then lettings_logs_path(status: [:completed], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all")
end
else
case type
when "lettings" then lettings_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all")
when "sales" then sales_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all")
when "schemes" then schemes_path(status: [:incomplete], owning_organisation_select: "all")
end
end
end
def view_all_path(type)
case type
when "lettings" then clear_filters_path(filter_type: "lettings_logs")
when "sales" then clear_filters_path(filter_type: "sales_logs")
when "schemes" then clear_filters_path(filter_type: "schemes")
when "misc" then clear_filters_path(filter_type: "schemes")
end
end
def view_all_text(type)
if type == "misc"
"View all schemes"
else
"View all #{type}"
end
end
ROLE_HEADINGS = {
"data_provider" => "Complete your logs",
"data_coordinator" => "Manage your data",
"support" => "Manage all data",
}.freeze
end

6
app/helpers/navigation_items_helper.rb

@ -4,6 +4,7 @@ module NavigationItemsHelper
def primary_items(path, current_user) def primary_items(path, current_user)
if current_user.support? if current_user.support?
[ [
NavigationItem.new("Home", root_path, home_current?(path)),
NavigationItem.new("Organisations", organisations_path, organisations_current?(path)), NavigationItem.new("Organisations", organisations_path, organisations_current?(path)),
NavigationItem.new("Users", users_path, users_current?(path)), NavigationItem.new("Users", users_path, users_current?(path)),
NavigationItem.new("Lettings logs", lettings_logs_path, lettings_logs_current?(path)), NavigationItem.new("Lettings logs", lettings_logs_path, lettings_logs_current?(path)),
@ -12,6 +13,7 @@ module NavigationItemsHelper
].compact ].compact
else else
[ [
NavigationItem.new("Home", root_path, home_current?(path)),
NavigationItem.new("Lettings logs", lettings_logs_path, lettings_logs_current?(path)), NavigationItem.new("Lettings logs", lettings_logs_path, lettings_logs_current?(path)),
NavigationItem.new("Sales logs", sales_logs_path, sales_logs_current?(path)), NavigationItem.new("Sales logs", sales_logs_path, sales_logs_current?(path)),
(NavigationItem.new("Schemes", schemes_path, non_support_supported_housing_schemes_current?(path)) if current_user.organisation.holds_own_stock? || current_user.organisation.stock_owners.present?), (NavigationItem.new("Schemes", schemes_path, non_support_supported_housing_schemes_current?(path)) if current_user.organisation.holds_own_stock? || current_user.organisation.stock_owners.present?),
@ -44,6 +46,10 @@ module NavigationItemsHelper
private private
def home_current?(path)
path == root_path || path == notifications_path
end
def lettings_logs_current?(path) def lettings_logs_current?(path)
path.starts_with?(lettings_logs_path) path.starts_with?(lettings_logs_path)
end end

17
app/helpers/notifications_helper.rb

@ -0,0 +1,17 @@
module NotificationsHelper
def notification_count
if current_user.present?
current_user.active_unread_notifications.count
else
Notification.active_unauthenticated_notifications.count
end
end
def notification
if current_user.present?
current_user.newest_active_unread_notification
else
Notification.newest_active_unauthenticated_notification
end
end
end

4
app/models/form_handler.rb

@ -28,6 +28,10 @@ class FormHandler
forms["current_lettings"] forms["current_lettings"]
end end
def previous_lettings_form
forms["previous_lettings"]
end
def current_sales_form def current_sales_form
forms["current_sales"] forms["current_sales"]
end end

14
app/models/notification.rb

@ -0,0 +1,14 @@
class Notification < ApplicationRecord
acts_as_readable
scope :active, -> { where("start_date <= ? AND end_date >= ?", Time.zone.now, Time.zone.now) }
scope :unauthenticated, -> { where(show_on_unauthenticated_pages: true) }
def self.active_unauthenticated_notifications
active.unauthenticated
end
def self.newest_active_unauthenticated_notification
active_unauthenticated_notifications.last
end
end

10
app/models/user.rb

@ -1,4 +1,6 @@
class User < ApplicationRecord class User < ApplicationRecord
acts_as_reader
# Include default devise modules. Others available are: # Include default devise modules. Others available are:
# :omniauthable # :omniauthable
devise :database_authenticatable, :recoverable, :rememberable, devise :database_authenticatable, :recoverable, :rememberable,
@ -227,6 +229,14 @@ class User < ApplicationRecord
sales_logs.after_date(FormHandler.instance.sales_earliest_open_for_editing_collection_start_date).duplicate_sets(id).map { |array_str| array_str ? array_str.map(&:to_i) : [] } sales_logs.after_date(FormHandler.instance.sales_earliest_open_for_editing_collection_start_date).duplicate_sets(id).map { |array_str| array_str ? array_str.map(&:to_i) : [] }
end end
def active_unread_notifications
Notification.active.unread_by(self)
end
def newest_active_unread_notification
active_unread_notifications.last
end
protected protected
# Checks whether a password is needed or not. For validations only. # Checks whether a password is needed or not. For validations only.

9
app/views/home/_data_box.html.erb

@ -0,0 +1,9 @@
<div class="app-data-box__upper">
<div class="app-data-box__count">
<%= govuk_link_to data_count(@current_user, type), data_path(@current_user, type), class: "govuk-link--no-visited-state govuk-link--no-underline" %>
</div>
<%= govuk_link_to data_subheading(@current_user, type), data_path(@current_user, type), class: "govuk-link--no-visited-state" %>
</div>
<div class="app-data-box__lower">
<%= govuk_link_to view_all_text(type), view_all_path(type), class: "govuk-link--inverse" %>
</div>

35
app/views/home/_upcoming_deadlines.html.erb

@ -0,0 +1,35 @@
<h1 class="govuk-heading-l">Upcoming deadlines</h1>
<% current_lettings_form = FormHandler.instance.in_crossover_period? ? FormHandler.instance.previous_lettings_form : FormHandler.instance.current_lettings_form %>
<% formatted_deadline = "#{current_lettings_form.submission_deadline.strftime('%A')} #{current_lettings_form.submission_deadline.to_formatted_s(:govuk_date)}" %>
<% if FormHandler.instance.in_crossover_period? %>
<p class="govuk-body govuk-body-m"><strong>End of year deadline - <%= formatted_deadline %>:</strong> Deadline to submit logs for tenancies starting between <%= collection_start_date(Time.zone.now).to_formatted_s(:govuk_date) %> to <%= collection_end_date(Time.zone.now).to_formatted_s(:govuk_date) %></p>
<% end %>
<% current_quarter = quarter_for_date(date: Time.zone.now) %>
<% if current_quarter.present? %>
<p class="govuk-body govuk-body-m"><strong><%= "#{current_quarter.quarter} - #{current_quarter.cutoff_date.strftime('%A')} #{current_quarter.cutoff_date.to_formatted_s(:govuk_date)}" %>:</strong> Quarterly cut off date for tenancies and sales starting between <%= current_quarter.quarter_start_date.to_formatted_s(:govuk_date) %> and <%= current_quarter.quarter_end_date.to_formatted_s(:govuk_date) %>.</p>
<% end %>
<% if !FormHandler.instance.in_crossover_period? %>
<p class="govuk-body govuk-body-m">Try to complete your logs for each quarter by the cut-off date.</p>
<p class="govuk-body govuk-body-m">You can still create logs for a previous quarter after its cut-off date, as long as you complete them by the <strong>end-of-year deadline: <%= formatted_deadline %>.</strong></p>
<% end %>
<% if FormHandler.instance.in_crossover_period? %>
<% previous_lettings_form = FormHandler.instance.previous_lettings_form %>
<p class="govuk-body govuk-body-m">Prioritise completing logs for the closing collection year. You must complete all <%= previous_lettings_form.start_date.year %> to <%= previous_lettings_form.submission_deadline.year %> logs must by the end-of-year deadline. You can still create <%= current_lettings_form.start_date.year %> to <%= current_lettings_form.submission_deadline.year %> logs for this quarter after the quarterly cut-off date.</p>
<% end %>
<%= govuk_details(summary_text: "Quarterly cut-off dates for 2023 to 2024") do %>
<p class="govuk-body govuk-body-m">The 2023 to 2024 quarterly cut-off dates are:</p>
<ul class="govuk-list govuk-list--bullet">
<li class="govuk-!-padding-bottom-4"><strong>Q1 - Friday 14 July 2023:</strong> Quarterly cut-off date for tenancies and sales starting between 1 April 2023 and 30 June 2023.</li>
<li class="govuk-!-padding-bottom-4"><strong>Q2 - Friday 13 October 2023:</strong> Quarterly cut-off date for tenancies and sales starting between 1 July 2023 and 30 September 2023.</li>
<li class="govuk-!-padding-bottom-4"><strong>Q3 - Friday 12 January 2024:</strong> Quarterly cut-off date for tenancies and sales starting between 1 October 2023 and 31 December 2023.</li>
<li class="govuk-!-padding-bottom-4"><strong>End of year deadline - Friday 7 June 2024:</strong> Deadline for tenancies and sales starting between 1 January 2024 and 31 March 2024, plus any late submissions for the 2023 to 2024 collection year.</li>
</ul>
<p class="govuk-body govuk-body-m">It is important that you meet these cut-off dates because we submit data to the Office for National Statistics quarterly, helping them create essential inflation statistics.</p>
<p class="govuk-body govuk-body-m">Meeting these cut-off dates also gives you more accurate data for your own analysis, and reduces the burden at the end of the year.</p>
<p class="govuk-body govuk-body-m">If you are not able to meet these quarterly dates, submit your logs as soon as you can so that they can be included in the annual data.</p>
<% end %>

58
app/views/home/index.html.erb

@ -0,0 +1,58 @@
<div class="govuk-grid-row">
<div class="govuk-width-container">
<div class="govuk-grid-column-two-thirds">
<div class="govuk-grid-row govuk-!-margin-bottom-7">
<span class="govuk-body-l"><%= "Welcome back, #{@current_user.name}" %></span>
<h1 class="govuk-heading-l"><%= heading_for_user_role(@current_user) %></h1>
</div>
<div class="govuk-grid-row">
<div class="app-data-box-group">
<% if @current_user.support? || (@current_user.data_coordinator? && @current_user.sales_logs.present?) %>
<div class="app-data-box-group-one-third">
<div class="app-data-box-one-third">
<span><%= render partial: "home/data_box", locals: { type: "lettings" } %></span>
</div>
<div class="app-data-box-one-third">
<span><%= render partial: "home/data_box", locals: { type: "sales" } %></span>
</div>
<div class="app-data-box-one-third">
<span><%= render partial: "home/data_box", locals: { type: "schemes" } %></span>
</div>
</div>
<% else %>
<div class="app-data-box-group-one-half">
<div class="app-data-box-one-half">
<span><%= render partial: "home/data_box", locals: { type: "lettings" } %></span>
</div>
<% if @current_user.data_coordinator? %>
<div class="app-data-box-one-half">
<span><%= render partial: "home/data_box", locals: { type: "schemes" } %></span>
</div>
<% elsif @current_user.sales_logs.present? %>
<div class="app-data-box-one-half">
<span><%= render partial: "home/data_box", locals: { type: "sales" } %></span>
</div>
<% else %>
<div class="app-data-box-one-half">
<span><%= render partial: "home/data_box", locals: { type: "misc" } %></span>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
<div class="govuk-grid-row">
<div class="app-data-box__underline">
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m govuk-!-margin-top-8 govuk-!-margin-bottom-8">
</div>
</div>
<div class="govuk-grid-row">
<%= render partial: "layouts/collection_resources" %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m govuk-!-margin-top-8 govuk-!-margin-bottom-8">
<%= render partial: "home/upcoming_deadlines" %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m govuk-!-margin-top-8 govuk-!-margin-bottom-8">
<%= render partial: "layouts/about_this_service" %>
</div>
</div>
</div>
</div>

7
app/views/layouts/_about_this_service.html.erb

@ -0,0 +1,7 @@
<% if current_user.present? %>
<h1 class="govuk-heading-l govuk-!-width-two-thirds">About this service</h1>
<% else %>
<h2 class="govuk-heading-m govuk-!-width-two-thirds">About this service</h2>
<% end %>
<p class="govuk-body">Submit social housing lettings and sales data (CORE) is a service that collects information about every new social housing letting and sale in England. The data you submit is used to make decisions about funding, regulations, and policies.</p>
<p class="govuk-body"><%= govuk_link_to "Learn more about statistics on social housing lettings (opens in a new tab)", "https://www.gov.uk/government/collections/rents-lettings-and-tenancies", target: "_blank" %></p>

115
app/views/layouts/_collection_resources.html.erb

@ -1,94 +1,59 @@
<div class="app-card"> <% if current_user %>
<h1 class="govuk-heading-l">Collection resources</h1>
<p class="govuk-body"><strong><%= govuk_link_to "Guidance for submitting social housing lettings and sales data (CORE)", guidance_path %></strong></p>
<% else %>
<h2 class="govuk-heading-m">Collection resources</h2> <h2 class="govuk-heading-m">Collection resources</h2>
<p class="govuk-body-s">For lettings starting during 1 April 2023 to 31 March 2024 and sales completing during the same period, use the 2023/24 forms.</p> <% end %>
<p class="govuk-body">Use the 2023 to 2024 forms for lettings that start and sales that complete between 1 April 2023 and 31 March 2024.</p>
<%= govuk_tabs(title: "Collection resources") do |c| %>
<% if FormHandler.instance.lettings_form_for_start_year(2023) && FormHandler.instance.lettings_form_for_start_year(2023).edit_end_date > Time.zone.today %> <% if FormHandler.instance.lettings_form_for_start_year(2023) && FormHandler.instance.lettings_form_for_start_year(2023).edit_end_date > Time.zone.today %>
<h3 class="govuk-heading-s">Lettings 2023/24</h3> <% c.with_tab(label: "Lettings 2023/24") do %>
<%= render DocumentListComponent.new(items: [ <%= render DocumentListComponent.new(items: [
{ {
name: "Lettings log for tenants (2023/24)", name: "Download the lettings log for tenants (2023 to 2024)",
href: download_23_24_lettings_form_path, href: download_23_24_lettings_form_path,
metadata: file_type_size_and_pages("2023_24_lettings_paper_form.pdf", number_of_pages: 8), metadata: file_type_size_and_pages("2023_24_lettings_paper_form.pdf", number_of_pages: 8),
}, },
{ {
name: "Lettings bulk upload template (2023/24) – New question ordering", name: "Download the lettings bulk upload template (2023 to 2024) – New question ordering",
href: download_23_24_lettings_bulk_upload_template_path, href: download_23_24_lettings_bulk_upload_template_path,
metadata: file_type_size_and_pages("bulk-upload-lettings-template-2023-24.xlsx"), metadata: file_type_size_and_pages("bulk-upload-lettings-template-2023-24.xlsx"),
}, },
{ {
name: "Lettings bulk upload template (2023/24)", name: "Download the lettings bulk upload template (2023 to 2024) – Legacy version",
href: download_23_24_lettings_bulk_upload_legacy_template_path, href: download_23_24_lettings_bulk_upload_legacy_template_path,
metadata: file_type_size_and_pages("bulk-upload-lettings-legacy-template-2023-24.xlsx"), metadata: file_type_size_and_pages("bulk-upload-lettings-legacy-template-2023-24.xlsx"),
}, },
{ {
name: "Lettings bulk upload specification (2023/24)", name: "Download the lettings bulk upload specification (2023 to 2024)",
href: download_23_24_lettings_bulk_upload_specification_path, href: download_23_24_lettings_bulk_upload_specification_path,
metadata: file_type_size_and_pages("bulk-upload-lettings-specification-2023-24.xlsx"), metadata: file_type_size_and_pages("bulk-upload-lettings-specification-2023-24.xlsx"),
}, },
]) %> ]) %>
<% end %>
<h3 class="govuk-heading-s">Sales 2023/24</h3> <% c.with_tab(label: "Sales 2023/24") do %>
<%= render DocumentListComponent.new(items: [ <%= render DocumentListComponent.new(items: [
{ {
name: "Sales log for buyers (2023/24)", name: "Download the sales log for buyers (2023 to 2024)",
href: download_23_24_sales_form_path, href: download_23_24_sales_form_path,
metadata: file_type_size_and_pages("2023_24_sales_paper_form.pdf", number_of_pages: 8), metadata: file_type_size_and_pages("2023_24_sales_paper_form.pdf", number_of_pages: 8),
}, },
{ {
name: "Sales bulk upload template (2023/24) – New question ordering", name: "Download the sales bulk upload template (2023 to 2024) – New question ordering",
href: download_23_24_sales_bulk_upload_template_path, href: download_23_24_sales_bulk_upload_template_path,
metadata: file_type_size_and_pages("bulk-upload-sales-template-2023-24.xlsx"), metadata: file_type_size_and_pages("bulk-upload-sales-template-2023-24.xlsx"),
}, },
{ {
name: "Sales bulk upload template (2023/24)", name: "Download the sales bulk upload template (2023 to 2024) – Legacy version",
href: download_23_24_sales_bulk_upload_legacy_template_path, href: download_23_24_sales_bulk_upload_legacy_template_path,
metadata: file_type_size_and_pages("bulk-upload-sales-legacy-template-2023-24.xlsx"), metadata: file_type_size_and_pages("bulk-upload-sales-legacy-template-2023-24.xlsx"),
}, },
{ {
name: "Sales bulk upload specification (2023/24)", name: "Download the sales bulk upload specification (2023 to 2024)",
href: download_23_24_sales_bulk_upload_specification_path, href: download_23_24_sales_bulk_upload_specification_path,
metadata: file_type_size_and_pages("bulk-upload-sales-specification-2023-24.xlsx"), metadata: file_type_size_and_pages("bulk-upload-sales-specification-2023-24.xlsx"),
}, },
]) %> ]) %>
<% end %> <% end %>
<% if FormHandler.instance.lettings_form_for_start_year(2022) && FormHandler.instance.lettings_form_for_start_year(2022).edit_end_date > Time.zone.today %>
<h3 class="govuk-heading-s">Lettings 2022/23</h3>
<%= render DocumentListComponent.new(items: [
{
name: "Lettings log for tenants (2022/23)",
href: download_22_23_lettings_form_path,
metadata: file_type_size_and_pages("2022_23_lettings_paper_form.pdf", number_of_pages: 4),
},
{
name: "Lettings bulk upload template (2022/23)",
href: download_22_23_lettings_bulk_upload_template_path,
metadata: file_type_size_and_pages("bulk-upload-lettings-template-2022-23.xlsx"),
},
{
name: "Lettings bulk upload specification (2022/23)",
href: download_22_23_lettings_bulk_upload_specification_path,
metadata: file_type_size_and_pages("bulk-upload-lettings-specification-2022-23.xlsx"),
},
]) %>
<h3 class="govuk-heading-s">Sales 2022/23</h3>
<%= render DocumentListComponent.new(items: [
{
name: "Sales log for buyers (2022/23)",
href: download_22_23_sales_form_path,
metadata: file_type_size_and_pages("2022_23_sales_paper_form.pdf", number_of_pages: 5),
},
{
name: "Sales bulk upload template (2022/23)",
href: download_22_23_sales_bulk_upload_template_path,
metadata: file_type_size_and_pages("bulk-upload-sales-template-2022-23.xlsx"),
},
{
name: "Sales bulk upload specification (2022/23)",
href: download_22_23_sales_bulk_upload_specification_path,
metadata: file_type_size_and_pages("bulk-upload-sales-template-2022-23.xlsx"),
},
]) %>
<% end %> <% end %>
</div> <% end %>

8
app/views/layouts/application.html.erb

@ -99,6 +99,10 @@
end end
end %> end %>
<% if notifications_to_display? %>
<%= render "notifications/notification_banner" %>
<% end %>
<% feedback_link = govuk_link_to "giving us your feedback (opens in a new tab)", t("feedback_form"), rel: "noreferrer noopener", target: "_blank" %> <% feedback_link = govuk_link_to "giving us your feedback (opens in a new tab)", t("feedback_form"), rel: "noreferrer noopener", target: "_blank" %>
<%= govuk_phase_banner( <%= govuk_phase_banner(
@ -107,7 +111,7 @@
text: "This is a new service – help us improve it by #{feedback_link}".html_safe, text: "This is a new service – help us improve it by #{feedback_link}".html_safe,
) %> ) %>
<% if !current_user.nil? %> <% if current_user.present? %>
<%= render PrimaryNavigationComponent.new( <%= render PrimaryNavigationComponent.new(
items: primary_items(request.path, current_user), items: primary_items(request.path, current_user),
) %> ) %>
@ -122,7 +126,7 @@
<%= govuk_notification_banner( <%= govuk_notification_banner(
title_text: "Success", title_text: "Success",
success: true, title_heading_level: 3, success: true, title_heading_level: 3,
title_id: "swanky-notifications" title_id: "flash-notice"
) do |notification_banner| ) do |notification_banner|
notification_banner.with_heading(text: flash.notice.html_safe) notification_banner.with_heading(text: flash.notice.html_safe)
if flash[:notification_banner_body] if flash[:notification_banner_body]

23
app/views/notifications/_notification_banner.html.erb

@ -0,0 +1,23 @@
<div class="app-unread-notification">
<div class="govuk-width-container">
<br>
<div class="govuk-grid-row">
<div class="govuk-grid-column-three-quarters">
<% if notification_count > 1 && current_user.present? %>
<p>Notification 1 of <%= notification_count %></p>
<% end %>
<p class="govuk-!-font-weight-bold"><%= notification.title %></p>
<% if notification.page_content.present? %>
<div class="govuk-body">
<%= govuk_link_to notification.link_text, notifications_path, class: "govuk-link--inverse govuk-!-font-weight-bold" %>
</div>
<% end %>
</div>
<% if current_user.present? %>
<p class="govuk-grid-column-one-quarter govuk-!-text-align-right ">
<%= govuk_link_to "Dismiss", dismiss_notifications_path, class: "govuk-link--inverse" %>
</p>
<% end %>
</div>
</div>
</div>

17
app/views/notifications/show.html.erb

@ -0,0 +1,17 @@
<% content_for :title, "Notification" %>
<% content_for :before_content do %>
<%= govuk_back_link(href: :back) %>
<% end %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-xl"><%= @notification.title %></h1>
<p>
<%= sanitize @notification.page_content %>
</p>
</div>
</div>
<br>
<div>
<%= govuk_button_link_to "Back to #{current_user.present? ? 'Home' : 'Start'}", root_path %>
</div>

4
app/views/organisations/show.html.erb

@ -41,8 +41,4 @@
<% end %> <% end %>
<%= render partial: "organisations/merged_organisation_details" %> <%= render partial: "organisations/merged_organisation_details" %>
</div> </div>
<div class="govuk-grid-column-one-third-from-desktop">
<%= render partial: "layouts/collection_resources" %>
</div>
</div> </div>

68
app/views/start/guidance.html.erb

@ -0,0 +1,68 @@
<h1 class="govuk-heading-l govuk-!-width-two-thirds">
Guidance for submitting social housing lettings and sales data
</h1>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<p class="govuk-body">This page includes details of when a CORE log is and is not required, what to do if a tenant or buyer is reluctant to answer questions in a log, and other information about submitting logs using CORE.</p>
<%= govuk_accordion do |accordion| %>
<%= accordion.with_section(heading_text: "How to create logs", expanded: true) do %>
<p class="govuk-body">There are 2 ways to create logs on CORE.</p>
<p class="govuk-body">You can create logs one at a time by answering questions using the online form. Click the “Create a new log” button on the logs page to create logs this way.</p>
<p class="govuk-body">You can also create many logs at once by uploading a CSV file. This might be faster than creating logs individually if your organisation has its own database and a way to export the data. Click the “Upload logs in bulk” button on the logs page to create logs this way. For more information, <%= govuk_link_to "read the full guidance on bulk upload", bulk_upload_lettings_log_path(id: "guidance", form: { year: current_collection_start_year }) %>.</p>
<p class="govuk-body">Once you have created and completed a log, there is nothing more you need to do to submit the data.</p>
<% end %>
<%= accordion.with_section(heading_text: "What scenarios require a new log?") do %>
<p class="govuk-body">For general needs, you should complete a log for each new tenancy intended to last 2 years or more if it is social rent or affordable rent, or of any length if it is intermediate rent.</p>
<p class="govuk-body">For supported housing, you should complete a log for each new letting of any length.</p>
<p class="govuk-body">If a new tenancy agreement is signed, create a new log.</p>
<% end %>
<%= accordion.with_section(heading_text: "Types of lettings you should create logs for") do %>
<p class="govuk-body">You’ll need to create a log for:</p>
<ul class="govuk-list govuk-list--bullet">
<li>Tenants in general needs housing allocated a new letting. This includes tenants moving into the social rented sector from outside, existing social tenants moving between properties or landlords, and existing social tenants renewing lettings in the same property. If fixed-term and social or affordable rent, only include tenancies of 2 years or more.</li>
<li>Tenants in supported housing (social housing, sheltered accommodation and care homes) allocated a new letting. This includes tenants moving into the social rented sector from outside, existing social tenants moving between properties or landlords, and existing social tenants renewing lettings in the same property. All supported housing tenancies should be reported regardless of length.</li>
<li>Starter tenancies provided by local authorities (LAs) and lettings with an introductory period provided by private registered providers (PRPs) should be completed in CORE at the beginning of the starter or introductory period. The tenancy type and length entered should be based on the tenancy the tenant will roll onto once the starter or introductory period has been completed. You do not need to submit another CORE log once the period has been completed.</li>
<li>Room moves within a shared housing unit that result in a different property type or support needs – this is classed as an internal transfer of an existing social tenant to another property.</li>
<li>Existing tenants who are issued with a new tenancy agreement when stock is acquired, transferred or permanently decanted.</li>
<li>Tenants under the Rough Sleepers Initiative or Rough Sleeping Accommodation Programme, where accommodation is permanent.</li>
<li>Households previously provided with temporary accommodation to meet a duty under the homelessness legislation who are allocated a tenancy as a settled home ending the duty (this may be the same property).</li>
<li>Refugees and asylum seekers who have been granted indefinite leave to remain, humanitarian protection or exceptional leave to remain.</li>
<li>Affordable Rent lettings – where up to 80% of market rent can be charged and a new supply agreement is signed.</li>
<li>London Affordable Rent lettings – a type of Affordable Rent available in London through the Greater London Authority (GLA).</li>
<li>Intermediate Rent lettings – where the rent must not exceed 80% of the current market rate (including any service charges).</li>
<li>Rent to Buy lettings – where a discount of up to 20% market rent is charged for a single rental period for a minimum of 5 years. After that period, the tenant is offered the chance to purchase the property (either shared ownership or outright) at full market value.</li>
<li>London Living Rent lettings – a type of Intermediate Rent available in London through the Greater London Authority (GLA).</li>
</ul>
<% end %>
<%= accordion.with_section(heading_text: "Types of lettings you should not create logs for") do %>
<p class="govuk-body">You don’t need to create a log for:</p>
<ul class="govuk-list govuk-list--bullet">
<li>Temporary general needs housing with a fixed period of less than 2 years if they are social or affordable rent. (Temporary lettings for intermediate rent and supported housing should be recorded).</li>
<li>Starter tenancies or lettings with an introductory period that roll onto or convert into the main tenancy. The CORE log should be completed at the beginning of this period.</li>
<li>Changes from sole to joint or joint to sole tenancies, where the number of people in the household has not changed.</li>
<li>Moves within a shared housing unit resulting in the same support needs or property type, even if a new tenancy or licence agreement is issued.</li>
<li>Lettings where no new tenancy agreement is signed.</li>
<li>Where stock is acquired, transferred or permanently decanted and the existing tenants are not issued with a new tenancy agreement.</li>
<li>Mutual exchanges including lettings where registered provider tenants have exchanged homes, for example through the national HOMESWAP system.</li>
<li>Successions and assignments.</li>
<li>Demotion of a secure or assured tenancy, and any subsequent conversion of the demoted tenancy to a secure or assured tenancy.</li>
<li>Lettings made to asylum seekers who are awaiting a decision on their applications for asylum under the Immigration and Asylum Act 1999.</li>
<li>Non-social lettings, including market-rented properties, employer-provided housing where the employer provides financial support, homes for staff of social landlords linked to employment, homes social landlords manage for organisations who are not social landlords, homes social landlords own but lease in entirety to organisations who are not social landlords, and freehold housing with variable charges for services and communal facilities.</li>
</ul>
<% end %>
<%= accordion.with_section(heading_text: "What if someone is reluctant to answer any questions?") do %>
<p class="govuk-body">If a tenant or buyer is reluctant to answer questions as part of a log, you should explain that:</p>
<ul class="govuk-list govuk-list--bullet">
<li>all information they provide is anonymous and will not affect their housing, benefits or other services they receive.</li>
<li>the data they provide is vital in helping to build a complete picture of social housing in England and is used to inform social housing policy.</li>
</ul>
<p class="govuk-body">If a tenant or buyer is still unwilling or unable to answer questions, select the ‘Don’t know’ or ‘Tenant/person prefers not to say’ options.</p>
<% end %>
<% end %>
</div>
</div>

9
app/views/start/index.html.erb

@ -16,13 +16,16 @@
href: start_path, href: start_path,
) %> ) %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m govuk-!-margin-bottom-8">
<h2 class="govuk-heading-m">Before you start</h2> <h2 class="govuk-heading-m">Before you start</h2>
<p class="govuk-body">Use your account details to sign in.</p> <p class="govuk-body">Use your account details to sign in.</p>
<p class="govuk-body">If you need to set up a new account, speak to your organisation’s CORE data coordinator. If you don’t know who that is, <%= govuk_link_to("contact the helpdesk", GlobalConstants::HELPDESK_URL) %>.</p> <p class="govuk-body">If you need to set up a new account, speak to your organisation’s CORE data coordinator. If you don’t know who that is, <%= govuk_link_to("contact the helpdesk", GlobalConstants::HELPDESK_URL) %>.</p>
<p class="govuk-body">You can <%= govuk_mail_to("dluhc.digital-services@levellingup.gov.uk", "request an account", subject: "CORE: Request a new account") %> if your organisation doesn’t have one.</p> <p class="govuk-body">You can <%= govuk_mail_to("dluhc.digital-services@levellingup.gov.uk", "request an account", subject: "CORE: Request a new account") %> if your organisation doesn’t have one.</p>
</div> <p class="govuk-body"><strong><%= govuk_link_to guidance_path do %>Guidance for submitting social housing lettings and sales data (CORE)<% end %></strong><p>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m govuk-!-margin-top-8 govuk-!-margin-bottom-8">
<div class="govuk-grid-column-one-third-from-desktop">
<%= render partial: "layouts/collection_resources" %> <%= render partial: "layouts/collection_resources" %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m govuk-!-margin-top-8 govuk-!-margin-bottom-8">
<%= render partial: "layouts/about_this_service" %>
</div> </div>
</div> </div>

5
config/routes.rb

@ -30,6 +30,7 @@ Rails.application.routes.draw do
resource :cookies, only: %i[show update] resource :cookies, only: %i[show update]
root to: "start#index" root to: "start#index"
get "/guidance", to: "start#guidance"
get "/logs", to: redirect("lettings-logs") get "/logs", to: redirect("lettings-logs")
get "/accessibility-statement", to: "content#accessibility_statement" get "/accessibility-statement", to: "content#accessibility_statement"
@ -127,6 +128,10 @@ Rails.application.routes.draw do
end end
end end
resource :notifications do
get "dismiss", to: "notifications#dismiss"
end
resources :organisations do resources :organisations do
get "duplicates", to: "duplicate_logs#index" get "duplicates", to: "duplicate_logs#index"

14
db/migrate/20240108145545_create_notification.rb

@ -0,0 +1,14 @@
class CreateNotification < ActiveRecord::Migration[7.0]
def change
create_table :notifications do |t|
t.string :title
t.string :link_text
t.string :page_content
t.datetime :start_date
t.datetime :end_date
t.boolean :show_on_unauthenticated_pages
t.timestamps
end
end
end

25
db/migrate/20240108152935_unread_migration.rb

@ -0,0 +1,25 @@
class UnreadMigration < ActiveRecord::Migration[6.0]
def self.up
create_table ReadMark, force: true, options: create_options do |t|
t.references :readable, polymorphic: { null: false }
t.references :reader, polymorphic: { null: false }
t.datetime :timestamp, null: false
t.timestamps
end
add_index ReadMark, %i[reader_id reader_type readable_type readable_id], name: "read_marks_reader_readable_index", unique: true
end
def self.down
drop_table ReadMark
end
def self.create_options
options = ""
if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) \
&& ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
options = "DEFAULT CHARSET=latin1"
end
options
end
end

24
db/schema.rb

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_12_18_105226) do ActiveRecord::Schema[7.0].define(version: 2024_01_08_152935) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -393,6 +393,17 @@ ActiveRecord::Schema[7.0].define(version: 2023_12_18_105226) do
t.string "new_organisation_telephone_number" t.string "new_organisation_telephone_number"
end end
create_table "notifications", force: :cascade do |t|
t.string "title"
t.string "link_text"
t.string "page_content"
t.datetime "start_date"
t.datetime "end_date"
t.boolean "show_on_unauthenticated_pages"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "organisation_relationships", force: :cascade do |t| create_table "organisation_relationships", force: :cascade do |t|
t.integer "child_organisation_id" t.integer "child_organisation_id"
t.integer "parent_organisation_id" t.integer "parent_organisation_id"
@ -446,6 +457,17 @@ ActiveRecord::Schema[7.0].define(version: 2023_12_18_105226) do
t.index ["old_visible_id"], name: "index_organisations_on_old_visible_id", unique: true t.index ["old_visible_id"], name: "index_organisations_on_old_visible_id", unique: true
end end
create_table "read_marks", force: :cascade do |t|
t.string "readable_type", null: false
t.bigint "readable_id"
t.string "reader_type", null: false
t.bigint "reader_id"
t.datetime "timestamp", precision: nil, null: false
t.index ["readable_type", "readable_id"], name: "index_read_marks_on_readable_type_and_readable_id"
t.index ["reader_id", "reader_type", "readable_type", "readable_id"], name: "read_marks_reader_readable_index", unique: true
t.index ["reader_type", "reader_id"], name: "index_read_marks_on_reader_type_and_reader_id"
end
create_table "sales_logs", force: :cascade do |t| create_table "sales_logs", force: :cascade do |t|
t.integer "status", default: 0 t.integer "status", default: 0
t.datetime "saledate" t.datetime "saledate"

10
spec/factories/notification.rb

@ -0,0 +1,10 @@
FactoryBot.define do
factory :notification do
title { "Notification title" }
link_text { "Link text" }
page_content { "Some html content" }
start_date { Time.zone.yesterday }
end_date { Time.zone.tomorrow }
show_on_unauthenticated_pages { false }
end
end

276
spec/features/home_page_spec.rb

@ -0,0 +1,276 @@
require "rails_helper"
require_relative "form/helpers"
RSpec.describe "Home Page Features" do
include Helpers
context "when there are notifications" do
let!(:user) { FactoryBot.create(:user) }
context "when the notifications are currently active" do
before do
create(:notification, title: "Notification title 1")
create(:notification, title: "Notification title 2")
create(:notification, title: "Notification title 3")
sign_in user
visit(root_path)
end
it "shows the latest notification with count and dismiss link" do
expect(page).to have_content("Notification 1 of 3")
expect(page).to have_content("Notification title 3")
expect(page).to have_link("Dismiss")
expect(page).to have_link("Link text")
end
context "when the user clicks a notification link" do
before do
click_link("Link text")
end
it "takes them to the notification details page" do
expect(page).to have_current_path(notifications_path)
expect(page).to have_content("Notification title 3")
expect(page).to have_content("Some html content")
expect(page).to have_link("Back to Home")
end
context "when they return" do
before do
click_link("Back to Home")
end
it "the notification has not been dismissed" do
expect(page).to have_current_path(root_path)
expect(page).to have_content("Notification 1 of 3")
expect(page).to have_content("Notification title 3")
expect(page).to have_link("Dismiss")
expect(page).to have_link("Link text")
end
end
end
context "when the user clicks a dismiss link" do
before do
click_link("Dismiss")
end
it "dismisses the notification and takes them back" do
expect(page).to have_current_path(root_path)
expect(page).to have_content("Notification 1 of 2")
expect(page).to have_content("Notification title 2")
expect(page).to have_link("Dismiss")
expect(page).to have_link("Link text")
end
context "when the user dismisses the penultimate notification" do
before do
click_link("Dismiss")
end
it "no longer displays the count" do
expect(page).to have_current_path(root_path)
expect(page).not_to have_content("Notification 1 of")
expect(page).to have_content("Notification title 1")
end
context "when the user dismisses the final notification" do
before do
click_link("Dismiss")
end
it "no longer displays any notification" do
expect(page).to have_current_path(root_path)
expect(page).not_to have_content("Notification")
expect(page).not_to have_link("Dismiss")
expect(page).not_to have_link("Link_text")
end
end
end
end
context "when another user has dismissed all their notifications" do
before do
other_user = create(:user)
Notification.mark_as_read! :all, for: other_user
visit(root_path)
end
it "the first user can still see the notifications" do
expect(page).to have_content("Notification 1 of 3")
expect(page).to have_content("Notification title 3")
expect(page).to have_link("Dismiss")
expect(page).to have_link("Link text")
end
end
end
context "when the notifications are not currently active" do
before do
create(:notification, end_date: Time.zone.yesterday, title: "Notification title 1")
create(:notification, start_date: Time.zone.tomorrow, title: "Notification title 2")
sign_in user
visit(root_path)
end
it "does not show any notifications" do
expect(page).not_to have_content("Notification title")
expect(page).not_to have_content("Notification 1 of")
expect(page).not_to have_link("Dismiss")
expect(page).not_to have_link("Link text")
end
end
end
context "when the user is a data provider" do
let(:user) { FactoryBot.create(:user, name: "Provider") }
before do
create_list(:lettings_log, 6, :in_progress, owning_organisation: user.organisation, created_by: user)
create_list(:lettings_log, 2, :in_progress, owning_organisation: user.organisation)
create_list(:lettings_log, 4, :completed, owning_organisation: user.organisation, created_by: user)
create_list(:lettings_log, 2, :completed)
sign_in user
visit(root_path)
end
it "displays the correct welcome text" do
expect(page).to have_current_path("/")
expect(page).to have_content("Welcome back, Provider")
expect(page).to have_content("Complete your logs")
end
context "when their organisation has submitted sales logs" do
before do
create_list(:sales_log, 5, :in_progress, owning_organisation: user.organisation, created_by: user)
create_list(:sales_log, 3, :completed, owning_organisation: user.organisation, created_by: user)
visit(root_path)
end
it "displays correct data boxes, counts and links" do
data_boxes = page.find_all(class: "app-data-box-one-half")
expect(data_boxes.count).to eq(2)
expect(data_boxes[0].all("a").map(&:text)).to eq(["6", "Your lettings in progress", "View all lettings"])
expect(data_boxes[0].all("a").map { |line| line["href"] }).to eq([lettings_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), lettings_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "lettings_logs")])
expect(data_boxes[1].all("a").map(&:text)).to eq(["5", "Your sales in progress", "View all sales"])
expect(data_boxes[1].all("a").map { |line| line["href"] }).to eq([sales_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), sales_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "sales_logs")])
end
end
context "when their organisation has never submitted sales logs" do
before do
visit(root_path)
end
it "displays correct data boxes, counts and links" do
data_boxes = page.find_all(class: "app-data-box-one-half")
expect(data_boxes.count).to eq(2)
expect(data_boxes[0].all("a").map(&:text)).to eq(["6", "Your lettings in progress", "View all lettings"])
expect(data_boxes[0].all("a").map { |line| line["href"] }).to eq([lettings_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), lettings_logs_path(status: [:in_progress], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "lettings_logs")])
expect(data_boxes[1].all("a").map(&:text)).to eq(["4", "Your completed lettings", "View all schemes"])
expect(data_boxes[1].all("a").map { |line| line["href"] }).to eq([lettings_logs_path(status: [:completed], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), lettings_logs_path(status: [:completed], assigned_to: "you", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "schemes")])
end
end
end
context "when the user is a data coordinator" do
before do
create_list(:lettings_log, 6, :in_progress, owning_organisation: user.organisation)
create_list(:lettings_log, 2, :in_progress, owning_organisation: user.organisation, created_by: user)
create_list(:lettings_log, 4, :completed, owning_organisation: user.organisation)
create_list(:lettings_log, 2, :completed)
create_list(:scheme, 1, :incomplete, owning_organisation: user.organisation)
sign_in user
visit(root_path)
end
let(:user) { FactoryBot.create(:user, :data_coordinator, name: "Coordinator") }
it "displays the correct welcome text" do
expect(page).to have_current_path("/")
expect(page).to have_content("Welcome back, Coordinator")
expect(page).to have_content("Manage your data")
end
context "when their organisation has submitted sales logs" do
before do
create_list(:sales_log, 5, :in_progress, owning_organisation: user.organisation)
create_list(:sales_log, 3, :completed, owning_organisation: user.organisation)
visit(root_path)
end
it "displays correct data boxes, counts and links" do
data_boxes = page.find_all(class: "app-data-box-one-third")
expect(data_boxes.count).to eq(3)
expect(data_boxes[0].all("a").map(&:text)).to eq(["8", "Lettings in progress", "View all lettings"])
expect(data_boxes[0].all("a").map { |line| line["href"] }).to eq([lettings_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), lettings_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "lettings_logs")])
expect(data_boxes[1].all("a").map(&:text)).to eq(["5", "Sales in progress", "View all sales"])
expect(data_boxes[1].all("a").map { |line| line["href"] }).to eq([sales_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), sales_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "sales_logs")])
expect(data_boxes[2].all("a").map(&:text)).to eq(["1", "Incomplete schemes", "View all schemes"])
expect(data_boxes[2].all("a").map { |line| line["href"] }).to eq([schemes_path(status: [:incomplete], owning_organisation_select: "all"), schemes_path(status: [:incomplete], owning_organisation_select: "all"), clear_filters_path(filter_type: "schemes")])
end
end
context "when their organisation has never submitted sales logs" do
before do
visit(root_path)
end
it "displays correct data boxes, counts and links" do
data_boxes = page.find_all(class: "app-data-box-one-half")
expect(data_boxes.count).to eq(2)
expect(data_boxes[0].all("a").map(&:text)).to eq(["8", "Lettings in progress", "View all lettings"])
expect(data_boxes[0].all("a").map { |line| line["href"] }).to eq([lettings_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), lettings_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "lettings_logs")])
expect(data_boxes[1].all("a").map(&:text)).to eq(["1", "Incomplete schemes", "View all schemes"])
expect(data_boxes[1].all("a").map { |line| line["href"] }).to eq([schemes_path(status: [:incomplete], owning_organisation_select: "all"), schemes_path(status: [:incomplete], owning_organisation_select: "all"), clear_filters_path(filter_type: "schemes")])
end
end
end
context "when the user is a support user" do
let(:support_user) { FactoryBot.create(:user, :support, name: "Support") }
let(:notify_client) { instance_double(Notifications::Client) }
let(:confirmation_token) { "MCDH5y6Km-U7CFPgAMVS" }
let(:devise_notify_mailer) { DeviseNotifyMailer.new }
let(:otp) { "999111" }
before do
create_list(:lettings_log, 2, :in_progress)
create_list(:lettings_log, 1, :completed)
create_list(:sales_log, 3, :in_progress)
create_list(:sales_log, 1, :completed)
create_list(:scheme, 1, :incomplete)
completed_scheme = create(:scheme)
create(:location, scheme: completed_scheme)
allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer)
allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client)
allow(Devise).to receive(:friendly_token).and_return(confirmation_token)
allow(notify_client).to receive(:send_email).and_return(true)
allow(SecureRandom).to receive(:random_number).and_return(otp)
visit("/lettings-logs")
fill_in("user[email]", with: support_user.email)
fill_in("user[password]", with: support_user.password)
click_button("Sign in")
fill_in("code", with: otp)
click_button("Submit")
visit(root_path)
end
it "displays the correct welcome text" do
expect(page).to have_current_path("/")
expect(page).to have_content("Welcome back, Support")
expect(page).to have_content("Manage all data")
end
it "displays correct data boxes, counts and links" do
data_boxes = page.find_all(class: "app-data-box-one-third")
expect(data_boxes.count).to eq(3)
expect(data_boxes[0].all("a").map(&:text)).to eq(["2", "Lettings in progress", "View all lettings"])
expect(data_boxes[0].all("a").map { |line| line["href"] }).to eq([lettings_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), lettings_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "lettings_logs")])
expect(data_boxes[1].all("a").map(&:text)).to eq(["3", "Sales in progress", "View all sales"])
expect(data_boxes[1].all("a").map { |line| line["href"] }).to eq([sales_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), sales_logs_path(status: [:in_progress], assigned_to: "all", years: [""], owning_organisation_select: "all", managing_organisation_select: "all"), clear_filters_path(filter_type: "sales_logs")])
expect(data_boxes[2].all("a").map(&:text)).to eq(["1", "Incomplete schemes", "View all schemes"])
expect(data_boxes[2].all("a").map { |line| line["href"] }).to eq([schemes_path(status: [:incomplete], owning_organisation_select: "all"), schemes_path(status: [:incomplete], owning_organisation_select: "all"), clear_filters_path(filter_type: "schemes")])
end
end
end

41
spec/features/notifications_page_spec.rb

@ -0,0 +1,41 @@
require "rails_helper"
require_relative "form/helpers"
RSpec.describe "Notifications Page Features" do
include Helpers
context "when there are notifications" do
let!(:user) { FactoryBot.create(:user) }
context "when the notifications are currently active" do
before do
create(:notification, title: "Notification title 1")
create(:notification, title: "Notification title 2")
create(:notification, title: "Notification title 3")
sign_in user
visit(notifications_path)
end
it "does not show the notification banner" do
expect(page).not_to have_content("Notification 1 of")
expect(page).not_to have_link("Dismiss")
expect(page).not_to have_link("Link text")
end
end
context "when the notifications are not currently active" do
before do
create(:notification, end_date: Time.zone.yesterday, title: "Notification title 1")
create(:notification, start_date: Time.zone.tomorrow, title: "Notification title 2")
sign_in user
visit(notifications_path)
end
it "does not show the notifications banner" do
expect(page).not_to have_content("Notification 1 of")
expect(page).not_to have_link("Dismiss")
expect(page).not_to have_link("Link text")
end
end
end
end

29
spec/features/start_page_spec.rb

@ -10,21 +10,38 @@ RSpec.describe "Start Page Features" do
sign_in user sign_in user
end end
it "takes you to logs" do it "takes you to the home page" do
visit("/") visit(root_path)
expect(page).to have_current_path("/lettings-logs") expect(page).to have_current_path("/")
expect(page).to have_content("Welcome back")
end end
end end
context "when the user is not signed in" do context "when the user is not signed in" do
it "takes you to sign in and then to logs" do it "takes you to sign in and then to the home page" do
visit("/") visit(root_path)
click_link("Start now") click_link("Start now")
expect(page).to have_current_path("/account/sign-in?start=true") expect(page).to have_current_path("/account/sign-in?start=true")
fill_in("user[email]", with: user.email) fill_in("user[email]", with: user.email)
fill_in("user[password]", with: user.password) fill_in("user[password]", with: user.password)
click_button("Sign in") click_button("Sign in")
expect(page).to have_current_path("/lettings-logs") expect(page).to have_current_path("/")
expect(page).to have_content("Welcome back")
end
context "when the unauthenticated user clicks a notification link" do
before do
create(:notification, show_on_unauthenticated_pages: true)
visit(root_path)
click_link("Link text")
end
it "takes them to the notification details page" do
expect(page).to have_current_path(notifications_path)
expect(page).to have_content("Notification title")
expect(page).to have_content("Some html content")
expect(page).to have_link("Back to Start")
end
end end
end end
end end

2
spec/features/test_spec.rb

@ -1,7 +1,7 @@
require "rails_helper" require "rails_helper"
RSpec.describe "Test Features" do RSpec.describe "Test Features" do
it "Displays the name of the app" do it "Displays the name of the app" do
visit("/") visit(root_path)
expect(page).to have_content("Submit social housing lettings and sales data (CORE)") expect(page).to have_content("Submit social housing lettings and sales data (CORE)")
end end

5
spec/features/user_spec.rb

@ -126,13 +126,14 @@ RSpec.describe "User Features" do
end end
it "Can navigate and sign in page with sign in button" do it "Can navigate and sign in page with sign in button" do
visit("/") visit(root_path)
expect(page).to have_link("Sign in") expect(page).to have_link("Sign in")
click_link("Sign in") click_link("Sign in")
fill_in("user[email]", with: user.email) fill_in("user[email]", with: user.email)
fill_in("user[password]", with: "pAssword1") fill_in("user[password]", with: "pAssword1")
click_button("Sign in") click_button("Sign in")
expect(page).to have_current_path("/lettings-logs") expect(page).to have_current_path("/")
expect(page).to have_content("Welcome back")
end end
it "tries to access account page, redirects to log in page" do it "tries to access account page, redirects to log in page" do

30
spec/helpers/collection_time_helper_spec.rb

@ -109,4 +109,34 @@ RSpec.describe CollectionTimeHelper do
end end
end end
end end
describe "#quarter_for_date" do
it "returns correct cutoff date for curent quarter" do
quarter = quarter_for_date(date: Time.zone.local(2023, 10, 1))
expect(quarter.cutoff_date).to eq(Time.zone.local(2024, 1, 12))
expect(quarter.quarter_start_date).to eq(Time.zone.local(2023, 10, 1))
expect(quarter.quarter_end_date).to eq(Time.zone.local(2023, 12, 31))
end
it "returns correct cutoff date for the first quarter of 2024/25" do
quarter = quarter_for_date(date: Time.zone.local(2024, 4, 1))
expect(quarter.cutoff_date).to eq(Time.zone.local(2024, 7, 12))
expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 4, 1))
expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 6, 30))
end
it "returns correct cutoff date for the second quarter of 2024/25" do
quarter = quarter_for_date(date: Time.zone.local(2024, 9, 30))
expect(quarter.cutoff_date).to eq(Time.zone.local(2024, 10, 11))
expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 7, 1))
expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 9, 30))
end
it "returns correct cutoff date for the third quarter of 2024/25" do
quarter = quarter_for_date(date: Time.zone.local(2024, 10, 25))
expect(quarter.cutoff_date).to eq(Time.zone.local(2025, 1, 10))
expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 10, 1))
expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 12, 31))
end
end
end end

95
spec/helpers/navigation_items_helper_spec.rb

@ -12,6 +12,7 @@ RSpec.describe NavigationItemsHelper do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false),
@ -21,7 +22,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the lettings logs item set as current" do
expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items)
end end
@ -34,6 +35,7 @@ RSpec.describe NavigationItemsHelper do
let(:stock_owner) { create(:organisation) } let(:stock_owner) { create(:organisation) }
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -44,15 +46,35 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the lettings logs item set as current" do
expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items)
end end
end end
end end
context "when the user is on the home page" do
let(:expected_navigation_items) do
[
NavigationItemsHelper::NavigationItem.new("Home", "/", true),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false),
NavigationItemsHelper::NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}/details", false),
NavigationItemsHelper::NavigationItem.new("Stock owners", "/organisations/#{current_user.organisation.id}/stock-owners", false),
NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false),
]
end
it "returns navigation items with the home item set as current" do
expect(primary_items("/", current_user)).to eq(expected_navigation_items)
end
end
context "when the user is on the lettings logs page" do context "when the user is on the lettings logs page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -63,7 +85,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the lettings logs item set as current" do
expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items)
end end
end end
@ -71,6 +93,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the sales logs page" do context "when the user is on the sales logs page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", true), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", true),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -81,7 +104,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the sales logs item set as current" do
expect(primary_items("/sales-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/sales-logs", current_user)).to eq(expected_navigation_items)
end end
end end
@ -89,6 +112,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the users page" do context "when the user is on the users page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -107,6 +131,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on their organisation details page" do context "when the user is on their organisation details page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -117,7 +142,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the organisation item set as current" do
expect(primary_items("/organisations/#{current_user.organisation.id}/details", current_user)).to eq(expected_navigation_items) expect(primary_items("/organisations/#{current_user.organisation.id}/details", current_user)).to eq(expected_navigation_items)
end end
end end
@ -125,6 +150,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the account page" do context "when the user is on the account page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -135,7 +161,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with no items set as current" do
expect(primary_items("/account", current_user)).to eq(expected_navigation_items) expect(primary_items("/account", current_user)).to eq(expected_navigation_items)
end end
end end
@ -143,6 +169,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the individual user's page" do context "when the user is on the individual user's page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -161,6 +188,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the individual scheme's page" do context "when the user is on the individual scheme's page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", true), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", true),
@ -171,7 +199,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with Schemes item set as current" do it "returns navigation items with schemes item set as current" do
expect(primary_items("/schemes/1", current_user)).to eq(expected_navigation_items) expect(primary_items("/schemes/1", current_user)).to eq(expected_navigation_items)
end end
end end
@ -191,6 +219,7 @@ RSpec.describe NavigationItemsHelper do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false),
@ -200,7 +229,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the lettings logs item set as current" do
expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items)
end end
@ -213,6 +242,7 @@ RSpec.describe NavigationItemsHelper do
let(:stock_owner) { create(:organisation) } let(:stock_owner) { create(:organisation) }
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false), NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
@ -223,7 +253,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the lettings logs item set as current" do
expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items)
end end
end end
@ -233,9 +263,27 @@ RSpec.describe NavigationItemsHelper do
context "when the user is a support user" do context "when the user is a support user" do
let(:current_user) { create(:user, :support) } let(:current_user) { create(:user, :support) }
context "when the user is on the home page" do
let(:expected_navigation_items) do
[
NavigationItemsHelper::NavigationItem.new("Home", "/", true),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
NavigationItemsHelper::NavigationItem.new("Sales logs", "/sales-logs", false),
NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false),
]
end
it "returns navigation items with the home item set as current" do
expect(primary_items("/", current_user)).to eq(expected_navigation_items)
end
end
context "when the user is on the lettings logs page" do context "when the user is on the lettings logs page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", true),
@ -244,7 +292,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the lettings logs item set as current" do
expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/lettings-logs", current_user)).to eq(expected_navigation_items)
end end
end end
@ -252,6 +300,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the sales logs page" do context "when the user is on the sales logs page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -260,7 +309,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the sales logs item set as current" do
expect(primary_items("/sales-logs", current_user)).to eq(expected_navigation_items) expect(primary_items("/sales-logs", current_user)).to eq(expected_navigation_items)
end end
end end
@ -268,6 +317,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the users page" do context "when the user is on the users page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", true), NavigationItemsHelper::NavigationItem.new("Users", "/users", true),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -284,6 +334,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the account page" do context "when the user is on the account page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -292,7 +343,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the no items set as current" do
expect(primary_items("/account", current_user)).to eq(expected_navigation_items) expect(primary_items("/account", current_user)).to eq(expected_navigation_items)
end end
end end
@ -300,6 +351,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the Schemes page" do context "when the user is on the Schemes page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -308,7 +360,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the users item set as current" do it "returns navigation items with the schemes item set as current" do
expect(primary_items("/schemes", current_user)).to eq(expected_navigation_items) expect(primary_items("/schemes", current_user)).to eq(expected_navigation_items)
end end
end end
@ -316,6 +368,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the individual user's page" do context "when the user is on the individual user's page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", true), NavigationItemsHelper::NavigationItem.new("Users", "/users", true),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -332,6 +385,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the individual scheme's page" do context "when the user is on the individual scheme's page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -347,7 +401,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with Schemes item set as current" do it "returns navigation items with schemes item set as current" do
expect(primary_items("/schemes/1", current_user)).to eq(expected_navigation_items) expect(primary_items("/schemes/1", current_user)).to eq(expected_navigation_items)
expect(scheme_items("/schemes/1", 1)).to eq(expected_scheme_items) expect(scheme_items("/schemes/1", 1)).to eq(expected_scheme_items)
end end
@ -356,6 +410,7 @@ RSpec.describe NavigationItemsHelper do
context "when the user is on the scheme locations page" do context "when the user is on the scheme locations page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -371,7 +426,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with Schemes item set as current" do it "returns navigation items with schemes item set as current" do
expect(primary_items("/schemes/1/locations", current_user)).to eq(expected_navigation_items) expect(primary_items("/schemes/1/locations", current_user)).to eq(expected_navigation_items)
expect(scheme_items("/schemes/1/locations", 1)).to eq(expected_scheme_items) expect(scheme_items("/schemes/1/locations", 1)).to eq(expected_scheme_items)
end end
@ -382,6 +437,7 @@ RSpec.describe NavigationItemsHelper do
let(:required_sub_path) { "lettings-logs" } let(:required_sub_path) { "lettings-logs" }
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -402,7 +458,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the logs item set as current" do it "returns navigation items with the lettings logs item set as current" do
expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items) expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items)
expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items) expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items)
end end
@ -412,6 +468,7 @@ RSpec.describe NavigationItemsHelper do
let(:required_sub_path) { "users" } let(:required_sub_path) { "users" }
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -432,7 +489,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the logs item set as current" do it "returns navigation items with the users item set as current" do
expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items) expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items)
expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items) expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items)
end end
@ -442,6 +499,7 @@ RSpec.describe NavigationItemsHelper do
let(:required_sub_path) { "schemes" } let(:required_sub_path) { "schemes" }
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -472,6 +530,7 @@ RSpec.describe NavigationItemsHelper do
let(:required_sub_path) { "details" } let(:required_sub_path) { "details" }
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Home", "/", false),
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false), NavigationItemsHelper::NavigationItem.new("Lettings logs", "/lettings-logs", false),
@ -492,7 +551,7 @@ RSpec.describe NavigationItemsHelper do
] ]
end end
it "returns navigation items with the logs item set as current" do it "returns navigation items with the organisation item set as current" do
expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items) expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items)
expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items) expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items)
end end

1
spec/requests/auth/passwords_controller_spec.rb

@ -67,7 +67,6 @@ RSpec.describe Auth::PasswordsController, type: :request do
put "/account/password", params: update_password_params put "/account/password", params: update_password_params
# Devise redirects once after re-sign in with new password and then root redirects as well. # Devise redirects once after re-sign in with new password and then root redirects as well.
follow_redirect! follow_redirect!
follow_redirect!
expect(page).to have_css("div", class: "govuk-notification-banner__heading", text: message) expect(page).to have_css("div", class: "govuk-notification-banner__heading", text: message)
end end
end end

1
spec/requests/maintenance_controller_spec.rb

@ -153,7 +153,6 @@ RSpec.describe MaintenanceController, type: :request do
end end
it "the cookie banner is visible" do it "the cookie banner is visible" do
follow_redirect!
follow_redirect! follow_redirect!
expect(page).to have_content("We’d like to use analytics cookies so we can understand how you use the service and make improvements.") expect(page).to have_content("We’d like to use analytics cookies so we can understand how you use the service and make improvements.")
end end

36
spec/requests/organisations_controller_spec.rb

@ -310,42 +310,6 @@ RSpec.describe OrganisationsController, type: :request do
it "redirects to details" do it "redirects to details" do
expect(response).to have_http_status(:redirect) expect(response).to have_http_status(:redirect)
end end
context "and 2022 collection window is open" do
let(:set_time) { allow(Time).to receive(:now).and_return(Time.zone.local(2023, 1, 1)) }
it "displays correct resources for 2022/23 and 2023/24 collection years" do
follow_redirect!
expect(page).to have_content("Lettings 2023/24")
expect(page).to have_content("Sales 2023/24")
expect(page).to have_content("Lettings 2022/23")
expect(page).to have_content("Sales 2022/23")
end
end
context "and 2022 collection window is closed for editing" do
let(:set_time) { allow(Time).to receive(:now).and_return(Time.zone.local(2024, 1, 1)) }
it "displays correct resources for 2022/23 and 2023/24 collection years" do
follow_redirect!
expect(page).to have_content("Lettings 2023/24")
expect(page).to have_content("Sales 2023/24")
expect(page).not_to have_content("Lettings 2022/23")
expect(page).not_to have_content("Sales 2022/23")
end
end
context "and 2023 collection window is closed for editing" do
let(:set_time) { allow(Time).to receive(:now).and_return(Time.zone.local(2025, 1, 1)) }
it "displays correct resources for 2022/23 and 2023/24 collection years" do
follow_redirect!
expect(page).not_to have_content("Lettings 2023/24")
expect(page).not_to have_content("Sales 2023/24")
expect(page).not_to have_content("Lettings 2022/23")
expect(page).not_to have_content("Sales 2022/23")
end
end
end end
context "with an organisation that are not in scope for the user, i.e. that they do not belong to" do context "with an organisation that are not in scope for the user, i.e. that they do not belong to" do

90
spec/requests/start_controller_spec.rb

@ -0,0 +1,90 @@
require "rails_helper"
RSpec.describe StartController, type: :request do
let(:user) { create(:user) }
let(:headers) { { "Accept" => "text/html" } }
let(:page) { Capybara::Node::Simple.new(response.body) }
let(:notify_client) { instance_double(Notifications::Client) }
let(:devise_notify_mailer) { DeviseNotifyMailer.new }
before do
allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer)
allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client)
allow(notify_client).to receive(:send_email).and_return(true)
end
describe "GET" do
context "when the user is not signed in" do
it "routes user to the start page" do
get "/", headers: headers, params: {}
expect(path).to eq("/")
expect(page).to have_content("Start now")
end
end
context "when the user is signed in" do
before do
sign_in user
end
it "routes user to the home page" do
get "/", headers:, params: {}
expect(page).to have_content("Welcome back")
end
context "and 2023 collection window is open for editing" do
before do
allow(Time).to receive(:now).and_return(Time.zone.local(2024, 1, 1))
end
it "displays correct resources for 2022/23 and 2023/24 collection years" do
get "/", headers: headers, params: {}
expect(page).to have_content("Lettings 2023/24")
expect(page).to have_content("Sales 2023/24")
end
end
context "and 2023 collection window is closed for editing" do
before do
allow(Time).to receive(:now).and_return(Time.zone.local(2025, 1, 1))
end
it "displays correct resources for 2022/23 and 2023/24 collection years" do
get "/", headers: headers, params: {}
expect(page).not_to have_content("Lettings 2023/24")
expect(page).not_to have_content("Sales 2023/24")
end
end
it "shows guidance link" do
get "/", headers: headers, params: {}
expect(page).to have_content("Guidance for submitting social housing lettings and sales data (CORE)")
end
it "displays About this service section" do
get "/", headers:, params: {}
expect(page).to have_content("About this service")
end
end
end
describe "guidance page" do
context "when the user is not signed in" do
it "routes user to the guidance page" do
get "/guidance", headers:, params: {}
expect(page).to have_content("Guidance for submitting social housing lettings and sales data")
end
end
context "when the user is signed in" do
before do
sign_in user
end
it "routes user to the guidance page" do
get "/guidance", headers:, params: {}
expect(page).to have_content("Guidance for submitting social housing lettings and sales data")
end
end
end
end

12
spec/requests/users_controller_spec.rb

@ -73,11 +73,11 @@ RSpec.describe UsersController, type: :request do
end end
describe "title link" do describe "title link" do
it "routes user to the /logs page" do it "routes user to the home page" do
sign_in user sign_in user
get "/", headers:, params: {} get "/", headers:, params: {}
follow_redirect! expect(path).to eq("/")
expect(path).to include("/lettings-logs") expect(page).to have_content("Welcome back")
expected_link = "<a class=\"govuk-header__link govuk-header__link--homepage\" href=\"/\">" expected_link = "<a class=\"govuk-header__link govuk-header__link--homepage\" href=\"/\">"
expect(CGI.unescape_html(response.body)).to include(expected_link) expect(CGI.unescape_html(response.body)).to include(expected_link)
end end
@ -2025,10 +2025,10 @@ RSpec.describe UsersController, type: :request do
sign_in user sign_in user
end end
it "routes user to the /logs page" do it "routes user to the home page" do
get "/", headers:, params: {} get "/", headers:, params: {}
follow_redirect! expect(path).to eq("/")
expect(path).to include("/lettings-logs") expect(page).to have_content("Welcome back")
expected_link = "<a class=\"govuk-header__link govuk-header__link--homepage\" href=\"/\">" expected_link = "<a class=\"govuk-header__link govuk-header__link--homepage\" href=\"/\">"
expect(CGI.unescape_html(response.body)).to include(expected_link) expect(CGI.unescape_html(response.body)).to include(expected_link)
end end

31
spec/views/layouts/application_layout_spec.rb

@ -54,4 +54,35 @@ RSpec.describe "layouts/application" do
include_examples "analytics cookie elements", banner: false, scripts: false include_examples "analytics cookie elements", banner: false, scripts: false
end end
context "with a notification present" do
context "when notification is shown on unauthenticated pages" do
before do
create(:notification, title: "Old notification title", show_on_unauthenticated_pages: true)
create(:notification, title: "New notification title", show_on_unauthenticated_pages: true)
render
end
it "shows the most recent notification without dismiss link or count" do
expect(rendered).to have_content("New notification title")
expect(rendered).to have_link("Link text")
expect(rendered).not_to have_link("Dismiss")
expect(rendered).not_to have_content("Notification 1 of")
end
end
context "when notification is not shown on unauthenticated pages" do
before do
create(:notification)
render
end
it "does not show the notification banner" do
expect(rendered).not_to have_content("Notification title")
expect(rendered).not_to have_link("Link text")
expect(rendered).not_to have_link("Dismiss")
expect(rendered).not_to have_content("Notification 1 of")
end
end
end
end end

Loading…
Cancel
Save