diff --git a/app/controllers/case_logs_controller.rb b/app/controllers/case_logs_controller.rb index 03000dfca..767e33046 100644 --- a/app/controllers/case_logs_controller.rb +++ b/app/controllers/case_logs_controller.rb @@ -7,7 +7,9 @@ class CaseLogsController < ApplicationController before_action :find_resource, except: %i[create index edit] def index - @pagy, @case_logs = pagy(current_user.case_logs) + set_session_filters if params[:status].present? + + @pagy, @case_logs = pagy(filtered_case_logs) respond_to do |format| format.html @@ -117,4 +119,16 @@ private def find_resource @case_log = CaseLog.find_by(id: params[:id]) end + + def filtered_case_logs + user_case_logs = current_user.case_logs + status_filter = JSON.parse(session[:case_logs_filters])["status"] if session[:case_logs_filters].present? + return user_case_logs unless status_filter + + user_case_logs.filter_by_status(status_filter) + end + + def set_session_filters + session[:case_logs_filters] = { status: params[:status] }.to_json + end end diff --git a/app/frontend/assets/images/icon-cross.svg b/app/frontend/assets/images/icon-cross.svg new file mode 100644 index 000000000..645525f8c --- /dev/null +++ b/app/frontend/assets/images/icon-cross.svg @@ -0,0 +1,3 @@ + diff --git a/app/frontend/controllers/filter_controller.js b/app/frontend/controllers/filter_controller.js new file mode 100644 index 000000000..ec55b72b5 --- /dev/null +++ b/app/frontend/controllers/filter_controller.js @@ -0,0 +1,16 @@ +import { Controller } from "@hotwired/stimulus"; + +export default class extends Controller { + toggleFilter() { + let filter_panel = document.getElementById("filter-panel"); + let toggle_filter_button = document.getElementById("toggle-filter-button"); + + if (filter_panel.style.display === "none" || !filter_panel.style.display) { + filter_panel.style.display = "block"; + toggle_filter_button.innerText = "Hide filters"; + } else { + filter_panel.style.display = "none"; + toggle_filter_button.innerText = "Show filters"; + } + } +} diff --git a/app/frontend/controllers/index.js b/app/frontend/controllers/index.js index ee3be6037..2227bea58 100644 --- a/app/frontend/controllers/index.js +++ b/app/frontend/controllers/index.js @@ -14,3 +14,6 @@ application.register("govukfrontend", GovukfrontendController) import NumericQuestionController from "./numeric_question_controller.js" application.register("numeric-question", NumericQuestionController) + +import FilterController from "./filter_controller.js" +application.register("filter", FilterController) diff --git a/app/frontend/styles/_filter.scss b/app/frontend/styles/_filter.scss new file mode 100644 index 000000000..46783534f --- /dev/null +++ b/app/frontend/styles/_filter.scss @@ -0,0 +1,123 @@ +.app-filter { + background-color: govuk-colour("light-grey"); + margin-bottom: govuk-spacing(2); +} + +.app-filter__header { + background-color: govuk-colour("light-grey"); + display: flex; + justify-content: space-between; + padding: govuk-spacing(2) govuk-spacing(3); + position: sticky; + top: 0; + z-index: 10; + + @include govuk-media-query($from: desktop) { + position: static; + } + + [class^="govuk-heading-"] { + margin-bottom: 0; + } +} + +.app-filter__content { + padding: govuk-spacing(1) govuk-spacing(3) govuk-spacing(4); +} + +.app-filter__close { + @include govuk-font(19); + + -webkit-appearance: none; + background-color: transparent; + border: none; + border-radius: 0; + color: $govuk-text-colour; + cursor: pointer; + margin: #{govuk-spacing(1) * -1}; + padding: govuk-spacing(1); + + &:focus { + background-color: $govuk-focus-colour; + color: $govuk-focus-text-colour; + box-shadow: 0 -2px $govuk-focus-colour, 0 4px $govuk-focus-text-colour; + outline: none; + } + + // Fix unwanted button padding in Firefox + &::-moz-focus-inner { + padding: 0; + border: 0; + } + + &::before { + background-image: url("../assets/images/icon-cross.svg"); + content: ""; + display: inline-block; + height: 14px; + margin-right: govuk-spacing(1); + position: relative; + top: -2px; // Alignment tweak + vertical-align: middle; + width: 14px; + } + + @include govuk-media-query(desktop) { + display: none; + } +} + +.app-filter-layout { + @include govuk-clearfix; +} + +.app-filter-toggle__button { + min-width: 128px; + @include govuk-media-query(desktop) { + display: none !important; + } +} + +.app-filter-layout__filter { + @include govuk-media-query(desktop) { + float: left; + min-width: govuk-grid-width("one-quarter"); + } + display: none; + + @include govuk-media-query(desktop) { + display: block; + } +} + +.js-enabled .app-filter-layout__filter { + outline: 0 none; + + @include govuk-media-query($until: desktop) { + background-color: govuk-colour("light-grey"); + bottom: govuk-spacing(1); + border: 1px solid govuk-colour("mid-grey"); + max-width: 310px; + min-width: 260px; + width: 100%; + overflow-y: scroll; + position: fixed; + right: govuk-spacing(1); + top: govuk-spacing(1); + z-index: 100; + + &:focus { + outline: $govuk-focus-width solid $govuk-focus-colour; + } + } +} + +.app-filter-layout__content { + @include govuk-media-query(desktop) { + float: right; + max-width: calc( + #{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)} + ); + width: 100%; + } +} diff --git a/app/frontend/styles/application.scss b/app/frontend/styles/application.scss index a89fa2cce..3d01074ec 100644 --- a/app/frontend/styles/application.scss +++ b/app/frontend/styles/application.scss @@ -1,9 +1,9 @@ @function frontend-font-url($filename) { - @return url("~assets/fonts/" + $filename); + @return url("~assets/fonts/"+$filename); } @function frontend-image-url($filename) { - @return url("~assets/images/" + $filename); + @return url("~assets/images/"+$filename); } $govuk-font-url-function: frontend-font-url; @@ -24,6 +24,7 @@ $govuk-global-styles: true; @import "template"; @import "pagination"; @import "panel"; +@import "filter"; // App utilities .app-\!-colour-muted { @@ -42,3 +43,9 @@ $govuk-global-styles: true; .govuk-tag { white-space: nowrap; } + +.button_to { + @include govuk-media-query($until: tablet) { + width: 100%; + } +} diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb new file mode 100644 index 000000000..aaee74fb6 --- /dev/null +++ b/app/helpers/filters_helper.rb @@ -0,0 +1,14 @@ +module FiltersHelper + def filter_selected?(filter) + return true unless session[:case_logs_filters] + + selected_filters = JSON.parse(session[:case_logs_filters]) + selected_filters["status"].present? && selected_filters["status"].include?(filter.to_s) + end + + def status_filters + statuses = {} + CaseLog.statuses.keys.map { |status| statuses[status] = status.humanize } + statuses + end +end diff --git a/app/models/case_log.rb b/app/models/case_log.rb index 6b602362f..aa926d5b4 100644 --- a/app/models/case_log.rb +++ b/app/models/case_log.rb @@ -34,6 +34,7 @@ class CaseLog < ApplicationRecord belongs_to :managing_organisation, class_name: "Organisation" scope :for_organisation, ->(org) { where(owning_organisation: org).or(where(managing_organisation: org)) } + scope :filter_by_status, ->(status) { where status: status } AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at].freeze OPTIONAL_FIELDS = %w[postcode_known la_known first_time_property_let_as_social_housing tenant_code propcode].freeze diff --git a/app/views/case_logs/_log_filters.erb b/app/views/case_logs/_log_filters.erb new file mode 100644 index 000000000..4e5593a62 --- /dev/null +++ b/app/views/case_logs/_log_filters.erb @@ -0,0 +1,32 @@ +