Skip to content

Commit

Permalink
Merge pull request #99 from TelosLabs/98-add-live-starting-soon-and-p…
Browse files Browse the repository at this point in the history
…ast-filter-for-sessions

Add status filters for Sessions
  • Loading branch information
Sergio-e authored Aug 17, 2024
2 parents 17b83df + bb2cb8d commit 9449924
Show file tree
Hide file tree
Showing 25 changed files with 343 additions and 40 deletions.
3 changes: 3 additions & 0 deletions app/assets/images/icons/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 11 additions & 5 deletions app/assets/images/icons/filters.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 9 additions & 5 deletions app/controllers/schedules_controller.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
class SchedulesController < ApplicationController
def show
@sessions = current_user.sessions
.where(conference: current_conference)
.order(:starts_at)
.includes(:attendees, :speakers, :location, :tags)
@sessions = SessionQuery.new(
relation: current_user.sessions.where(conference: current_conference),
params: filter_params
).call.includes(:attendees, :location, :speakers, :tags).order(:starts_at)
end

private

@sessions = @sessions.starts_at(params[:starts_at].to_date) if params[:starts_at].present?
def filter_params
params.permit(:starts_at, :live, :past, :starting_soon)
end
end
15 changes: 8 additions & 7 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
class SessionsController < ApplicationController
def index
@user_session_ids = current_user.sessions.pluck(:id)
@sessions = sessions
.joins(:location)
.includes(:attendees, :tags)
.order(:starts_at)
.distinct

@sessions = @sessions.starts_at(params[:starts_at].to_date) if params[:starts_at].present?
@sessions = SessionQuery.new(
relation: sessions.joins(:location).distinct,
params: filter_params
).call.includes(:attendees, :tags).order(:starts_at)
end

def show
Expand All @@ -20,4 +17,8 @@ def show
def sessions
current_conference&.sessions
end

def filter_params
params.permit(:starts_at, :live, :past, :starting_soon)
end
end
16 changes: 16 additions & 0 deletions app/helpers/session_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module SessionHelper
def session_filter_color(scope)
case scope
when "live"
"bg-green-500"
when "past"
"bg-blue-teal-light"
when "starting_soon"
"bg-yellow"
end
end

def session_filter_params
params.permit(SessionQuery::STATUS_SCOPES)
end
end
4 changes: 3 additions & 1 deletion app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { application } from 'controllers/application'

// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from '@hotwired/stimulus-loading'
eagerLoadControllersFrom('controllers', application)
import Dropdown from '@stimulus-components/dropdown'

// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
// lazyLoadControllersFrom("controllers", application)
eagerLoadControllersFrom('controllers', application)
application.register('dropdown', Dropdown)
15 changes: 15 additions & 0 deletions app/models/application_record.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class

class << self
def send_chain_or(scopes)
return all if scopes.blank?

base_scope = none

scopes.each do |scope_name|
scope_to_add = send(scope_name)
base_scope = (base_scope == none) ? scope_to_add : base_scope.or(scope_to_add)
end

base_scope
end
end
end
19 changes: 18 additions & 1 deletion app/models/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,26 @@ class Session < ApplicationRecord

validates_datetime :ends_at, after: :starts_at

scope :starts_at, ->(date) { where(starts_at: date.all_day) }
scope :starts_at, ->(date) { where("date(starts_at) = ?", date) }
scope :past, -> { where(ends_at: ...Time.current) }
scope :live, -> { where("? BETWEEN starts_at AND ends_at", Time.current) }
scope :starting_soon, -> { where("starts_at BETWEEN ? and ?", Time.current, 1.hour.from_now) }

def self.ransackable_attributes(_auth_object = nil)
%w[title]
end

def live?
Time.current.between?(starts_at, ends_at)
end

def starting_soon?
return false if starts_at < Time.current

(starts_at - Time.current) < 1.hour
end

def past?
ends_at < Time.current
end
end
39 changes: 39 additions & 0 deletions app/queries/session_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class SessionQuery
STATUS_SCOPES = %w[live starting_soon past].freeze

def initialize(relation: Session.all, params: {})
@relation = relation
@params = params
end

def call
filter_by_date
filter_by_status

relation
end

private

attr_accessor :relation, :params

def filter_by_date
return if starts_at.blank?

self.relation = relation.starts_at(starts_at)
end

def filter_by_status
self.relation = relation.send_chain_or(status_scopes)
end

def starts_at
@_starts_at ||= params[:starts_at]&.to_date
rescue Date::Error
nil
end

def status_scopes
STATUS_SCOPES & params.keys
end
end
2 changes: 1 addition & 1 deletion app/views/schedules/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
}
) %>
<% end %>
<% elsif params[:starts_at].present? %>
<% elsif params[:starts_at].present? || session_filter_params.present? %>
<div class="flex flex-col items-center justify-center w-full h-full">
<p class="max-w-xs mb-4 font-bold text-center">No sessions match your current filters</p>
<%= link_to 'Clear filters', schedule_path, class: "text-red underline font-bold italic text-lg" %>
Expand Down
29 changes: 29 additions & 0 deletions app/views/sessions/_card.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@

<div class="flex flex-col w-full p-5 mb-4 bg-white rounded-[20px]">
<div class="flex flex-col w-full">
<% if session.live? %>
<div class="h-8 px-4 py-2 bg-green-500 rounded-lg bg-opacity-[.08] justify-center items-center inline-flex mb-4">
<div class="grow basis-0 h-4 justify-center items-center gap-2 flex">
<span class="relative flex h-4 w-4">
<span class="animate-slow-ping absolute inline-flex h-full w-full rounded-full bg-green-500 opacity-75"></span>
<span class="rounded-full h-4 w-4 bg-green-500"></span>
</span>
<span class="w-full text-xs">Session is live now.</span>
</div>
</div>
<% elsif session.starting_soon? %>
<div class="h-8 px-4 py-2 bg-yellow rounded-lg bg-opacity-[.08] justify-center items-center inline-flex mb-4">
<div class="grow basis-0 h-4 justify-center items-center gap-2 flex">
<span class="relative flex h-4 w-4">
<span class="rounded-full h-4 w-4 bg-yellow"></span>
</span>
<span class="w-full text-xs">Session is starting soon.</span>
</div>
</div>
<% elsif session.past? %>
<div class="h-8 px-4 py-2 bg-blue-teal-light rounded-lg bg-opacity-[.08] justify-center items-center inline-flex mb-4">
<div class="grow basis-0 h-4 justify-center items-center gap-2 flex">
<span class="relative flex h-4 w-4">
<span class="rounded-full h-4 w-4 bg-blue-teal-light"></span>
</span>
<span class="w-full text-xs">Session is over.</span>
</div>
</div>
<% end %>
<% if speaker %>
<div class="flex justify-between w-full mb-4">
<div class="flex">
Expand Down
79 changes: 75 additions & 4 deletions app/views/sessions/_filters.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div class="flex items-center gap-2 overflow-x-scroll no-scrollbar">
<%= link_to(
'All dates',
url_for(resource),
url_for([resource, session_filter_params.to_h]),
class: [
"flex min-w-fit items-center justify-center px-4 py-2 rounded-full font-medium",
"bg-red text-white": params[:starts_at].blank?,
Expand All @@ -14,7 +14,7 @@
<% current_conference.session_dates.each do |session_date| %>
<%= link_to(
session_date.strftime("%a, %d"),
url_for([resource, starts_at: session_date]),
url_for([resource, session_filter_params.to_h.merge(starts_at: session_date)]),
class: [
"flex min-w-fit items-center justify-center px-4 py-2 font-medium rounded-full",
"bg-red text-white": params[:starts_at] == session_date.to_s,
Expand All @@ -24,7 +24,78 @@
<% end %>
</div>

<div class="flex items-center justify-center ml-3 p-2 bg-white rounded-full min-w-[40px] min-h-[40px]">
<%= inline_svg_tag("icons/filters.svg", size: "18") %>
<div class="flex items-center justify-center ml-3 p-2 rounded-full min-w-[40px] min-h-[40px] <%= session_filter_params.present? ? "bg-red fill-white" : "bg-white fill-red" %>">
<div class="relative" data-controller="dropdown">
<button type="button" data-action="dropdown#toggle click@window->dropdown#hide" class="flex items-center justify-center p-2 rounded-full">
<%= inline_svg_tag("icons/filters.svg", size: "18") %>
</button>

<div
data-dropdown-target="menu"
class="hidden transition transform origin-top-right absolute right-0"
data-transition-enter-from="opacity-0 scale-95"
data-transition-enter-to="opacity-100 scale-100"
data-transition-leave-from="opacity-100 scale-100"
data-transition-leave-to="opacity-0 scale-95">
<div class="pt-2 pb-2 bg-white rounded-lg shadow-[0_10px_50px_0_rgba(0,0,0,0.40)] flex-col inline-flex absolute top-4 right-[-8px] right-0 w-40 max-w-40">
<%= form_with url: resource, class: "grid", method: :get do |form| %>
<%= form.hidden_field :starts_at, value: params[:starts_at] %>
<% SessionQuery::STATUS_SCOPES.each do |name| %>
<div class="self-stretch px-4 py-2 items-center gap-2 inline-flex">
<%= form.check_box(
name, checked: params[name] == "1",
class: "w-4 h-4 rounded text-red",
skip_base_styling: true, include_hidden: false
) %>
<div class="text-gray-800">
<%= form.label name, class: "text-base font-medium" do %>
<%= t("views.status_filters.#{name}") %>
<% end %>
</div>
</div>
<% end %>
<div class="h-6 px-2.5 py-4 rounded justify-center items-center gap-2.5 inline-flex">
<div class="text-lg text-red italic underline font-black">
<%= form.submit(
t("views.status_filters.submit"),
name: "",
class: "text-lg text-red italic underline font-black"
) %>
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>

<% if session_filter_params.present? %>
<div class="flex w-full mb-2 gap-2">
<div class="flex flex-wrap ">
<div class="h-8 py-1 text-base font-bold leading-tight">Active filters:</div>
</div>
<div class="flex flex-wrap gap-2">
<% SessionQuery::STATUS_SCOPES.each do |name| %>
<% next unless params[name] == "1" %>
<% bg_color = session_filter_color(name) %>
<div class="h-8 px-4 py-2 <%= bg_color %> bg-opacity-[.08] rounded-lg gap-2 inline-flex">
<div class="gap-2 flex">
<div class="w-4 h-4 <%= bg_color %> rounded-full"></div>
<div class="text-xs font-medium"><%= t("views.status_filters.#{name}") %></div>
</div>
<div class="w-4 h-4">
<% modified_params = request.query_parameters.deep_dup %>
<% modified_params.delete(name) %>
<%= link_to(
inline_svg_tag("icons/close.svg"),
url_for([resource, modified_params])
) %>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
2 changes: 1 addition & 1 deletion app/views/sessions/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
}
) %>
<% end %>
<% elsif params[:starts_at].present? %>
<% elsif params[:starts_at].present? || session_filter_params.present? %>
<div class="flex flex-col items-center justify-center w-full h-full">
<p class="max-w-xs mb-4 font-bold text-center">No sessions match your current filters</p>
<%= link_to 'Clear filters', sessions_path, class: "text-red underline font-bold italic text-lg" %>
Expand Down
18 changes: 16 additions & 2 deletions app/views/sessions/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
) do %>
<%= inline_svg_tag("icons/bookmark-outline.svg") %>
<% end %>
<% end %>
<% end %>
</div>
<% end %>
</div>
Expand All @@ -42,7 +42,21 @@
<% else %>
<div class="flex flex-row justify-between w-full grow">
<h1 class="text-[20px] text-red italic mb-4 font-bold"><%= @session.title %></h1>
<%= inline_svg_tag "icon_bookmark.svg", class: "fill-red stroke-red min-w-4 min-h-4 w-4 h-4 mt-2 ml-5" %>
<% if current_user.sessions.pluck(:id).include?(@session.id) %>
<%= button_to(
session_attendee_path(session_id: @session.id, params: request.params[:starts_at]),
method: :delete, form_class: "flex items-center ml-5 mb-4"
) do %>
<%= inline_svg_tag("icons/bookmark-full.svg") %>
<% end %>
<% else %>
<%= button_to(
session_attendee_path(session_id: @session.id, params: request.params[:starts_at]),
form_class: "flex items-center ml-5 mb-4"
) do %>
<%= inline_svg_tag("icons/bookmark-outline.svg") %>
<% end %>
<% end %>
</div>
<% end %>
Expand Down
4 changes: 3 additions & 1 deletion config/importmap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

pin "application"
pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin "@hotwired/stimulus", to: "@hotwired--stimulus.js" # @3.2.2
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
pin_all_from "app/javascript/controllers", under: "controllers"
pin "@stimulus-components/dropdown", to: "@stimulus-components--dropdown.js" # @3.0.0
pin "stimulus-use" # @0.52.2
pin_all_from "app/javascript/custom", under: "custom"
6 changes: 6 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ en:
notice: "Session was added to My Schedule"
remove_user:
notice: "Session was removed from My Schedule"
views:
status_filters:
past: "Past"
live: "Live"
starting_soon: "Starting soon"
submit: "Apply"
authorization:
unauthorized: "You are not authorized to access this page."
session_mailer:
Expand Down
Loading

0 comments on commit 9449924

Please sign in to comment.