Skip to content

Commit

Permalink
Merge pull request #235 from lnu-norge/inline-editing-facilities
Browse files Browse the repository at this point in the history
Inline editing for facilities
  • Loading branch information
DanielJackson-Oslo authored Feb 29, 2024
2 parents 25638ef + a9ed0ec commit 1085b2a
Show file tree
Hide file tree
Showing 23 changed files with 325 additions and 303 deletions.
1 change: 1 addition & 0 deletions app/assets/stylesheets/common_elements.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
a,
.link {
@apply cursor-pointer;
@apply text-pink-700;
@apply rounded;
&:hover {
Expand Down
23 changes: 17 additions & 6 deletions app/assets/stylesheets/editable.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@
}
.edit-button {
@apply rounded-lg py-2 px-3;

&.edit-button--small {
@apply rounded-lg py-1 px-1.5;
@apply text-sm;
}

@apply bg-gray-100 border border-gray-100;
@apply inline-flex gap-2 content-center items-center;
@apply text-gray-700;

&.collapsable {
@apply gap-0;

.text {
max-width: 0;
overflow: hidden;
Expand All @@ -28,11 +32,18 @@
&:hover {
@apply shadow-md;
@apply border border-pink-700;
&.collapsable {
.text {
max-width: 200px;
margin-right: 0.5em;
}
}
}
}

.collapsable-wrapper:hover .collapsable,
.edit-button.collapsable:hover {
.text {
max-width: 200px;
margin-right: 0.5em;
}
}

.collapsable-wrapper:hover .edit-button {
@apply shadow-md;
@apply border border-pink-700;
}
31 changes: 19 additions & 12 deletions app/controllers/facility_reviews_controller.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
# frozen_string_literal: true

class FacilityReviewsController < BaseControllers::AuthenticateController
def new
@space = Space.find(params["space_id"])
@categories = FacilityCategory.all
include DefineGroupedFacilitiesForSpace

@reviews_for_categories = @space.reviews_for_categories(current_user)
def new
params.require([:space_id, :facility_id, :facility_category_id])

@grouped_relevant_facilities = @space.relevant_space_facilities(grouped: true)
@non_relevant_facilities = @space.non_relevant_space_facilities
@grouped_non_relevant_facilities = @space.group_space_facilities(@non_relevant_facilities)
@space = Space.find(params[:space_id])
@facility = Facility.find(params[:facility_id])
@space_facility = SpaceFacility.find_by(space: @space, facility: @facility)
@facility_review = FacilityReview.find_or_initialize_by(facility: @facility, space: @space, user: current_user)
@experiences = FacilityReview::LIST_EXPERIENCES

@experiences = [
"unknown",
*FacilityReview.experiences.keys.reverse
].reverse
define_category
end

def create
Expand Down Expand Up @@ -54,7 +52,8 @@ def redirect_and_show_flash(flash_message:, flash_type: :notice, redirect_status
respond_to do |format|
format.turbo_stream do
flash.now[flash_type] = flash_message
@grouped_relevant_facilities = @space.relevant_space_facilities(grouped: true)

define_facilities
render turbo_stream: [
turbo_stream.update(:flash,
partial: "shared/flash"),
Expand Down Expand Up @@ -133,4 +132,12 @@ def nothing_changed(review, existing_review)

existing_review.present? && existing_review[:experience] == review["experience"]
end

def define_category
@category = if params[:facility_category_id].present?
FacilityCategory.find(params[:facility_category_id])
else
Facility.find(params[:facility_id]).facility_categories.first
end
end
end
5 changes: 4 additions & 1 deletion app/controllers/spaces_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class SpacesController < BaseControllers::AuthenticateController # rubocop:disable Metrics/ClassLength
include DefineGroupedFacilitiesForSpace

def index
@spaces = Space.order updated_at: :desc
@space = Space.new
Expand All @@ -9,7 +11,8 @@ def index
def show
@space = Space.includes(:space_contacts).where(id: params[:id]).first
@space_contact = SpaceContact.new(space_id: @space.id, space_group_id: @space.space_group_id)
@grouped_relevant_facilities = @space.relevant_space_facilities(grouped: true)

define_facilities
end

def new
Expand Down
1 change: 1 addition & 0 deletions app/models/facility.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class Facility < ApplicationRecord
has_many :facilities_categories, dependent: :destroy
has_many :facility_categories, through: :facilities_categories
has_many :facility_reviews, dependent: :destroy

has_many :space_types_facilities, dependent: :destroy
has_many :space_types, through: :space_types_facilities
Expand Down
5 changes: 5 additions & 0 deletions app/models/facility_review.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ def experience_icon
ICON_FOR_EXPERIENCE[experience]
end

LIST_EXPERIENCES = [
"unknown",
*FacilityReview.experiences.keys.reverse
].reverse

ICON_FOR_EXPERIENCE = {
"was_allowed" => "likely",
"was_not_allowed" => "unlikely",
Expand Down
99 changes: 59 additions & 40 deletions app/models/space.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,74 +152,93 @@ def score_from_star_rating
(star_rating - 2.9) / 10
end

# Groups all of the users facility reviews into a hash like
# { category_id: { facility_id: review } }
def reviews_for_categories(user)
user.facility_reviews
.where(space: self)
.includes(facility: [:facilities_categories])
.joins(facility: [:facilities_categories])
.each_with_object({}) do |review, memo|
review.facility.facilities_categories.each do |facility_category|
memo[facility_category.facility_category_id] ||= {}
memo[facility_category.facility_category_id][review.facility.id] = review
end
end
end

# Space Facilities that are typically relevant for the space
# Either because they share a space type with the space
# or because someone has said that they are relevant for
# this specific space by setting a space_facilities experience.
#
# Can be grouped by category by passing grouped: true
def relevant_space_facilities(grouped: false)
relevant = space_facilities.includes(facility: [:facilities_categories]).where(relevant: true)

return relevant unless grouped

group_space_facilities(relevant)
end

# Facilities (found through space facilities) that are relevant.
def relevant_facilities
space_facilities.includes(:facility).where(relevant: true).map(&:facility)
# Can be grouped by category by passing grouped: true, and
# if a user is defined, include facility reviews for that user
def relevant_space_facilities(grouped: false, user: nil)
filtered_space_facilities(relevant: true, grouped:, user:)
end

# Space Facilities that are typically NOT relevant for the space
# Because they DO NOT share a space type with the space AND
# no one has given a space_facility experience for them.
#
# Can be grouped by category by passing grouped: true
# Can be grouped by category by passing grouped: true.
# Cannot have facility reviews, else they would be relevant.
def non_relevant_space_facilities(grouped: false)
non_relevant = space_facilities.includes(facility: [:facilities_categories]).where(relevant: false)
filtered_space_facilities(relevant: false, grouped:)
end

return non_relevant unless grouped
def filtered_space_facilities(relevant: true, grouped: false, user: nil)
ungrouped_facilities = space_facilities
.includes(
facility: [
:facility_reviews,
:facilities_categories
]
)
.where(relevant:)
.order("facilities.title")

group_space_facilities(non_relevant)
return ungrouped_facilities unless grouped

group_space_facilities(ungrouped_facilities:, user:)
end

# Facilities (found through space facilities) that are relevant.
def relevant_facilities
space_facilities.includes(:facility).where(relevant: true).map(&:facility)
end

# Groups given facilities by their category
# { category_id: [facility_1, facility_2, ...] }
def group_space_facilities(ungrouped_facilities) # rubocop:disable Metrics/AbcSize
def group_space_facilities(ungrouped_facilities:, user: nil)
ungrouped_facilities.each_with_object({}) do |space_facility, memo|
space_facility.facility.facilities_categories.each do |facility_category|
memo[facility_category.facility_category_id] ||= {
category: facility_category.facility_category,
space_facilities: []
}
memo[facility_category.facility_category_id][:space_facilities] << {
id: space_facility.facility.id,
title: space_facility.facility.title,
description: space_facility.description,
review: space_facility.experience,
space_types: space_facility.facility.space_types,
relevant: space_facility.relevant
}

facility_data = facility_data_from_space_facility(space_facility:, facility_category:, user:)

memo[facility_category.facility_category_id][:space_facilities] << facility_data
end
end.sort_by(&:first) # sorts by category id
end

def facility_data_from_space_facility(space_facility:, facility_category:, user:)
data = {
id: space_facility.facility.id,
title: space_facility.facility.title,
description: space_facility.description,
review: space_facility.experience,
space_types: space_facility.facility.space_types,
relevant: space_facility.relevant,
category_id: facility_category.facility_category.id
}

add_current_user_review_to_data(data:, space_facility:, user:)
end

def add_current_user_review_to_data(data:, space_facility:, user:)
return data if user.blank?

if space_facility.facility.facility_reviews.present?
current_user_review = space_facility.facility.facility_reviews.find_by(user:,
space: self)
end

data[:current_user_review] =
(current_user_review.presence || FacilityReview.new(facility_id: id, space_id: @space, user_id: user.id))

data
end

def merge_paper_trail_versions
PaperTrail::Version
.or(PaperTrail::Version.where(item: self))
Expand Down
8 changes: 8 additions & 0 deletions app/models/space_facility.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def not_relevant!
def not_relevant?
!relevant?
end

def user_review(user)
FacilityReview.find_or_initialize_by(
user:,
facility:,
space:
)
end
end

# == Schema Information
Expand Down
4 changes: 2 additions & 2 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def name
"#{first_name} #{last_name[0]&.upcase}."
end

def new_facility_review_for(facility_id, space)
FacilityReview.new(
def facility_review_for(facility_id, space)
FacilityReview.find_or_initialize_by(
space:,
facility_id:,
user: self
Expand Down
7 changes: 4 additions & 3 deletions app/services/spaces/aggregate_facility_reviews_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ def aggregate_reviews(facility) # rubocop:disable Metrics/AbcSize
return handle_zero_facility_reviews(space_facility, belongs_to_space_type) if count.zero?

# Set criteria:
positive_threshold = reviews.positive.count >= (count / 3.0 * 2.0).ceil
impossible_threshold = reviews.impossible.count >= (count / 2.0).ceil
negative_threshold = reviews.negative.count >= (count / 3.0 * 2.0).ceil
two_out_of_three = (count / 3.0 * 2.0).ceil
positive_threshold = reviews.positive.count >= two_out_of_three
impossible_threshold = reviews.impossible.count >= two_out_of_three
negative_threshold = reviews.negative.count >= two_out_of_three

set_relevance(space_facility, belongs_to_space_type, positive_threshold)

Expand Down
28 changes: 28 additions & 0 deletions app/views/facility_reviews/_facility_with_edit_button.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<%# locals: (title:, tooltip:, space_id:, facility_review:, experience:, facility_category_id:, facility_id:, description: %>
<%= turbo_frame_tag dom_id(facility_review, "category_#{facility_category_id}__facility_#{facility_id}__") do %>
<%= link_to new_facility_review_path(
space_id:,
facility_id:,
facility_category_id:,
),
title: tooltip,
class: 'unstyled-link inline-flex gap-2 items-center collapsable-wrapper' do %>

<h4 class="text-base <%= "line-through text-gray-600" if experience == "impossible" %>"><%= title %></h4>

<%= inline_svg_tag "facility_status/#{experience}", class: "#{" text-black " if experience == "impossible" }" %>

<span class="edit-button edit-button--small collapsable">
<span class="text">
<%= t('space_edit.edit') %>
</span>
<%= inline_svg_tag 'edit', alt: t('space_edit.edit'), title: t('space_edit.edit') %>
</span>
<% end %>
<% unless description.nil? %>
<div class="text-gray-400 mb-1.5">
<%= description %>
</div>
<% end %>
<% end %>
Loading

0 comments on commit 1085b2a

Please sign in to comment.