Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions app/controllers/bookmarks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,35 @@ class BookmarksController < ApplicationController
before_action :set_breadcrumb

def index
per_page = params[:number_of_items_per_page] || 25
bookmarks = Bookmark.search(params)
@bookmarks = bookmarks.paginate(page: params[:page], per_page: 25)
@bookmarks_count = bookmarks.size
bookmarks = bookmarks.sorted(params[:sort])

@bookmarks = bookmarks.paginate(page: params[:page], per_page: per_page)
@bookmarks_count = bookmarks.length
@windows_types_array = WindowsType::TYPES
load_sortable_fields
set_index_variables
respond_to do |format|
format.html
format.js
end
end

def personal
per_page = params[:number_of_items_per_page] || 25
user = User.where(id: params[:user_id]).first if params[:user_id].present?
user ||= current_user
@user_name = user.full_name if user
@viewing_self = user == current_user

bookmarks = Bookmark.search(params, user: user)
@bookmarks_count = bookmarks.size
@bookmarks = bookmarks.paginate(page: params[:page], per_page: 25)
@windows_types_array = WindowsType::TYPES
bookmarks = bookmarks.sorted(params[:sort])

@bookmarks_count = bookmarks.length
@bookmarks = bookmarks.paginate(page: params[:page], per_page: per_page)

set_index_variables

load_sortable_fields
respond_to do |format|
format.html
format.js
Expand Down Expand Up @@ -97,9 +104,12 @@ def tally

private

def load_sortable_fields
def set_index_variables
@sortable_fields = WindowsType.where("name NOT LIKE ?", "%COMBINED%")
@windows_types = WindowsType.all
@windows_types_array = WindowsType::TYPES
bookmarkable_types = Bookmark::BOOKMARKABLE_MODELS
@bookmarkable_types = bookmarkable_types.map{ |type| [ type, type ] }

end

def load_workshop_data
Expand Down
10 changes: 10 additions & 0 deletions app/decorators/bookmark_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,14 @@ def bookmarkable_link
bookmarkable.breadcrumb_link
end
end

def bookmarkable_image_url(fallback: 'missing.png')
if bookmarkable.respond_to?(:images) && bookmarkable.images.first&.file&.attached?
Rails.application.routes.url_helpers.rails_blob_path(bookmarkable.images.first.file, only_path: true)
elsif bookmarkable_type == "Workshop"
ActionController::Base.helpers.asset_path("workshop_default.jpg")
else
ActionController::Base.helpers.asset_path(fallback)
end
end
end
21 changes: 2 additions & 19 deletions app/decorators/facilitator_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,8 @@ def description
"Facilitator Profile for #{first_name} #{last_name}"
end

DISPLAY_FIELDS = {
"First name" => :first_name,
"Last name" => :last_name,
"Primary email address" => :primary_email_address,
"Primary email type" => :primary_email_address_type,
"Street address" => :street_address,
"City" => :city,
"State" => :state,
"ZIP" => :zip,
"Country" => :country,
"Mailing address type" => :mailing_address_type,
"Phone number" => :phone_number,
"Phone number type" => :phone_number_type
}

def display_fields
DISPLAY_FIELDS.map do |label, method|
{ label: label, value: object.send(method) }
end
def inactive?
!user ? false : user&.inactive?
end

def pronouns_display
Expand Down
10 changes: 9 additions & 1 deletion app/models/application_record.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end

def bookmarks_count
if self.respond_to?(:bookmarks)
self.bookmarks.length
else
0
end
end
end
124 changes: 79 additions & 45 deletions app/models/bookmark.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,39 @@ class Bookmark < ApplicationRecord
belongs_to :user
belongs_to :bookmarkable, polymorphic: true

BOOKMARKABLE_MODELS = ["CommunityNews", "Event", "Facilitator", "Project", "Resource", "Story", "StoryIdea",
"Workshop", "WorkshopIdea", "WorkshopLog", "WorkshopVariation"]

scope :for_workshops, -> { where(bookmarkable_type: 'Workshop') }
scope :bookmarkable_type, -> (bookmarkable_type) { bookmarkable_type.present? ? where(bookmarkable_type: bookmarkable_type) : all }
scope :bookmarkable_attributes, -> (bookmarkable_type, bookmarkable_id) {
bookmarkable_type.present? && bookmarkable_id.present? ? where(bookmarkable_type: bookmarkable_type,
bookmarkable_id: bookmarkable_id) : all }

scope :sort_by_newest, -> { order(created_at: :desc) }
scope :sort_by_popularity, -> {
select("bookmarks.*, COUNT(all_b.id) as popularity")
.joins("LEFT JOIN bookmarks all_b ON all_b.bookmarkable_id = bookmarks.bookmarkable_id AND
all_b.bookmarkable_type = bookmarks.bookmarkable_type")
.group("bookmarks.id")
.order("popularity DESC") }


def self.search(params, user: nil)
bookmarks = user ? user.bookmarks : self.all
bookmarks = bookmarks.filter_by_params(params)
bookmarks = bookmarks.sorted(params[:sort])
bookmarks
end

sort = params[:sort].presence || "title"

case sort
when "title"
bookmarks = bookmarks
.joins(<<~SQL)
LEFT JOIN workshops ON bookmarks.bookmarkable_type = 'Workshop' AND workshops.id = bookmarks.bookmarkable_id
-- LEFT JOIN stories ON bookmarks.bookmarkable_type = 'Story' AND stories.id = bookmarks.bookmarkable_id
LEFT JOIN resources ON bookmarks.bookmarkable_type = 'Resource' AND resources.id = bookmarks.bookmarkable_id
LEFT JOIN events ON bookmarks.bookmarkable_type = 'Event' AND events.id = bookmarks.bookmarkable_id
SQL
.order(Arel.sql("COALESCE(workshops.title, resources.title, events.title) ASC")) # stories.title,
when "led"
bookmarks = bookmarks.where(bookmarkable_type: "Workshop")
.joins("INNER JOIN workshops ON bookmarks.bookmarkable_id = workshops.id")
.order("workshops.led_count DESC")
when "bookmark_count"
counts = bookmarks.group(:bookmarkable_type, :bookmarkable_id)
.select(:bookmarkable_type, :bookmarkable_id, "COUNT(*) AS total_bookmarks")
bookmarks = bookmarks
.joins("LEFT JOIN (#{counts.to_sql}) AS counts
ON counts.bookmarkable_type = bookmarks.bookmarkable_type
AND counts.bookmarkable_id = bookmarks.bookmarkable_id")
.order(Arel.sql("COALESCE(counts.total_bookmarks,0) DESC"))
when "created"
bookmarks = bookmarks.order(created_at: :desc)
def self.sorted(sort_by=nil) # sort and sort_by are namespaced
sort_by ||= "newest"
case sort_by
when "newest" then self.sort_by_newest
when "title" then self.sort_by_title
when "popularity" then self.sort_by_popularity
else self.sort_by_newest
end

bookmarks
end

def self.filter_by_params(params={})
Expand All @@ -49,26 +43,74 @@ def self.filter_by_params(params={})
bookmarks = bookmarks.bookmarkable_type(params[:bookmarkable_type])
bookmarks = bookmarks.bookmarkable_attributes(params[:bookmarkable_type],
params[:bookmarkable_id])
bookmarks = bookmarks.title(params[:title])
bookmarks = bookmarks.user_name(params[:user_name])
bookmarks = bookmarks.windows_type(params[:windows_type])
bookmarks = bookmarks.title(params[:title]) if params[:title].present?
bookmarks = bookmarks.user_name(params[:user_name]) if params[:user_name].present?
bookmarks = bookmarks.windows_type(params[:windows_type]) if params[:windows_type].present?

bookmarks
end

def self.sort_by_title
bookmarks = self.joins(<<~SQL)
LEFT JOIN community_news ON community_news.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'CommunityNews'
LEFT JOIN events ON events.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Event'
LEFT JOIN facilitators ON facilitators.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Facilitator'
LEFT JOIN projects ON projects.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Project'
LEFT JOIN resources ON resources.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Resource'
LEFT JOIN stories ON stories.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Story'
LEFT JOIN story_ideas ON story_ideas.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'StoryIdea'
LEFT JOIN workshops ON workshops.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Workshop'
LEFT JOIN workshop_ideas ON workshop_ideas.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'WorkshopIdea'
LEFT JOIN workshop_logs ON workshop_logs.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'WorkshopLog'
LEFT JOIN workshop_variations ON workshop_variations.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'WorkshopVariation'
SQL
bookmarks.order(Arel.sql(<<~SQL.squish)
LOWER(
COALESCE(
community_news.title,
events.title,
CONCAT(facilitators.first_name, ' ', facilitators.last_name),
projects.name,
resources.title,
stories.title,
story_ideas.title,
workshops.title,
workshop_ideas.title,
DATE_FORMAT(workshop_logs.date, '%Y-%m-%d'),
workshop_variations.name
)
) ASC,
bookmarks.created_at DESC
SQL
)
end

def self.title(title)
return all unless title.present?

bookmarks = self.all
bookmarks = bookmarks.joins(<<~SQL)
LEFT JOIN workshops ON workshops.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Workshop'
-- LEFT JOIN stories ON stories.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Story'
LEFT JOIN resources ON resources.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Resource'
LEFT JOIN events ON events.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Event'
LEFT JOIN community_news ON community_news.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'CommunityNews'
LEFT JOIN events ON events.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Event'
LEFT JOIN facilitators ON facilitators.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Facilitator'
LEFT JOIN projects ON projects.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Project'
LEFT JOIN resources ON resources.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Resource'
LEFT JOIN stories ON stories.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Story'
LEFT JOIN story_ideas ON story_ideas.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'StoryIdea'
LEFT JOIN workshops ON workshops.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Workshop'
LEFT JOIN workshop_ideas ON workshop_ideas.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'WorkshopIdea'
LEFT JOIN workshop_logs ON workshop_logs.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'WorkshopLog'
LEFT JOIN workshop_variations ON workshop_variations.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'WorkshopVariation'
SQL

bookmarks.where(
"workshops.title LIKE :title OR events.title LIKE :title OR resources.title LIKE :title", # OR stories.title LIKE :title
"community_news.title LIKE :title OR events.title LIKE :title OR facilitators.first_name LIKE :title OR
facilitators.last_name LIKE :title OR projects.name LIKE :title OR resources.title LIKE :title OR
stories.title LIKE :title OR workshops.title LIKE :title OR workshop_ideas.title LIKE :title OR
story_ideas.body LIKE :title OR -- searching body for story ideas (title exists but isn't used in UI)
DATE_FORMAT(workshop_logs.date, '%Y-%m-%d') LIKE :title OR -- no title on workshop_logs
workshop_variations.name LIKE :title -- searching name for workshop variations (title doesn't exist)
",
title: "%#{title}%"
)
end
Expand Down Expand Up @@ -143,13 +185,5 @@ def self.user_name(user_name)
)
end

def bookmarkable_image_url(fallback: 'missing.png')
if bookmarkable.respond_to?(:images) && bookmarkable.images.first&.file&.attached?
Rails.application.routes.url_helpers.rails_blob_path(bookmarkable.images.first.file, only_path: true)
elsif bookmarkable_type == "Workshop"
ActionController::Base.helpers.asset_path("workshop_default.jpg")
else
ActionController::Base.helpers.asset_path(fallback)
end
end

end
52 changes: 32 additions & 20 deletions app/views/bookmarks/_personal_row.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<!-- Image -->
<div class="w-12 h-8 bg-gray-100 rounded overflow-hidden">
<%= link_to polymorphic_path(bookmarkable) do %>
<%= image_tag(bookmark.bookmarkable_image_url, class: "object-cover w-full h-full",
<%= image_tag(bookmark.decorate.bookmarkable_image_url, class: "object-cover w-full h-full",
alt: "#{ bookmarkable.object.class.name } image") %>
<% end %>
</div>
Expand All @@ -32,52 +32,64 @@


<!-- 2️⃣ Title / author / metadata -->
<div class="flex flex-col gap-1 min-w-[40ch] max-w-[40ch] break-words">
<div class="flex flex-col gap-1 min-w-[60ch] max-w-[60ch] break-words">
<h3 class="text-lg font-bold text-gray-800 flex items-center gap-2">
<%= link_to "#{bookmarkable.title}#{" [HIDDEN]" if bookmarkable.inactive?}",
<% if bookmarkable.respond_to?(:type) %>
<% type_name = " (#{bookmarkable.type})" %>
<% elsif bookmarkable.respond_to?(:windows_type) %>
<% type_name = " (#{bookmarkable.windows_type.short_name})" if bookmarkable.windows_type %>
<% else %>
<% type_name = "" %>
<% end %>

<%= link_to "#{bookmarkable.title}#{ type_name }#{" [HIDDEN]" if bookmarkable.inactive?}",
polymorphic_path(bookmarkable),
class: "hover:underline",
data: { turbo: false, } %>
</h3>
<div class="text-sm text-gray-600">
You bookmarked on
<%= bookmark.created_at.strftime("%B %d, %Y") %>
</div>
<div class="text-sm text-gray-600">
Bookmarked by community
<%= bookmark.bookmarkable.bookmarks_count %> times
</div>
</div>

<!-- 3️⃣ Description -->
<div class="flex-1 text-sm text-gray-700">
<div class="text-sm text-gray-600">
Author:
<% if bookmark.bookmarkable_type == "Workshop" && bookmarkable.user %>
<%= link_to bookmarkable.author_name,
Created by:
<% if bookmarkable.respond_to?(:user) && bookmarkable.user %>
<%= link_to bookmarkable.user.full_name,
generate_facilitator_user_path(bookmarkable.user),
class: "hover:underline",
data: { turbo: false, } %>
<% elsif bookmark.bookmarkable_type == "Workshop" %>
<%= bookmarkable.full_name.present? ? bookmarkable.full_name : "Facilitator" %>
<% elsif bookmarkable.respond_to?(:created_by) %>
<%= bookmarkable.created_by.present? ? bookmarkable.created_by.name : "User" %>
<% elsif bookmarkable.respond_to?(:created_by) && bookmarkable.created_by %>
<%= link_to bookmarkable.object.created_by.full_name,
generate_facilitator_user_path(bookmarkable.created_by),
class: "hover:underline",
data: { turbo: false, } %>
<% else %>
User
<% end %>
</div>

<div class="text-sm text-gray-600">
<span>
Type/date:
<% if bookmark.bookmarkable_type == "Workshop" && bookmarkable.windows_type.present? %>
<%= "#{bookmarkable.windows_type.short_name} - #{bookmarkable.date}" %>
<% elsif bookmark.bookmarkable_type == "Event" %>
Date:
<% if bookmark.bookmarkable_type == "Workshop" || bookmark.bookmarkable_type == "Event" %>
<%= bookmarkable.date %>
<% else %>
<%= bookmarkable.created_at.strftime("%B %d, %Y") %>
<% end %>
<% if bookmark.bookmarkable_type == "Workshop" && bookmarkable.age_ranges.any? %>
(<%= bookmarkable.age_ranges.pluck(:name).to_sentence %>)
<br>Age ranges: <%= bookmarkable.age_ranges.pluck(:name).to_sentence %>
<% end %>
</span>
</div>

<div class="text-sm text-gray-600">
<span>
Bookmarked on:
<%= bookmark.created_at.strftime("%B %d, %Y") %>
</span>
</div>
</div>
</div>
10 changes: 2 additions & 8 deletions app/views/bookmarks/_search_fields.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,9 @@
<%= label_tag :bookmarkable_type, "Bookmark type", class: "block text-sm font-medium text-gray-700 mb-1" %>
<div class="relative">
<%= select_tag :bookmarkable_type,
options_for_select([["All types", ""],
["Workshops", "Workshop"],
["Stories", "Story"],
["Resources", "Resource"],
["Community news", "CommunityNews"],
["Events", "Event"],
],
options_for_select(@bookmarkable_types,
params[:bookmarkable_type]),
include_blank: "All types",
class: "w-full rounded-lg border border-gray-300 px-3 py-2 text-gray-800 shadow-sm
focus:border-blue-500 focus:ring focus:ring-blue-200 focus:outline-none",
onchange: "this.form.submit()" %>
Expand All @@ -62,7 +57,6 @@

<!-- Clear filters / placeholder for additional fields -->
<div class="flex items-center space-x-2">
<%#= render 'workshops/windows_type_fields', windows_types: @windows_types %>
<%= link_to 'Clear filters', bookmarks_path, class: "btn btn-utility-outline" %>
</div>
</div>
Loading