Skip to content

Commit 82137ae

Browse files
njaegginilsrauch
authored andcommitted
Add agenda list filters (#2538)
1 parent d269732 commit 82137ae

19 files changed

Lines changed: 529 additions & 88 deletions

File tree

app/controllers/agenda_controller.rb

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,51 @@ class AgendaController < ApplicationController
99
skip_before_action :authenticate_person!
1010
skip_authorization_check
1111

12-
layout "agenda"
12+
before_action :set_default_type_filter, only: :index
13+
before_action :set_default_date_range_filter, only: :index, unless: :turbo_frame_request?
14+
before_action :preload_filter_select_options, only: :index, unless: :turbo_frame_request?
1315

14-
helper_method :group, :events, :event
16+
layout -> { turbo_frame_request? ? false : "agenda" }
17+
18+
helper_method :group, :events, :event, :event_filter
1519

1620
def index
17-
init_filter_values
21+
if turbo_frame_request?
22+
render partial: "agenda/list", locals: {events: events}
23+
else
24+
render :index
25+
end
1826
end
1927

2028
def show
2129
end
2230

2331
private
2432

25-
def init_filter_values
26-
set_date_range
27-
set_event_type
33+
def set_default_type_filter
34+
params[:filters] ||= {}
35+
params[:filters][:type] ||= {types: [Event::Tour.sti_name]}
2836
end
2937

30-
def set_date_range
38+
def set_default_date_range_filter
3139
params[:filters] ||= {}
32-
params[:filters][:date_range] ||= {
33-
since: I18n.l(Time.zone.today.to_date)
34-
}
40+
params[:filters][:date_range] ||= {since: I18n.l(Time.zone.today.to_date)}
3541
end
3642

37-
def set_event_type
38-
params[:filters] ||= {}
39-
params[:filters][:type] ||= {types: ["Event::Tour"]}
43+
def preload_filter_select_options
44+
@target_groups = Event::TargetGroup.list.without_deleted
45+
@activities = Event::Activity.list.without_deleted
46+
@technical_requirements = Event::TechnicalRequirement.list.without_deleted
47+
@fitness_requirements = Event::FitnessRequirement.list.without_deleted
4048
end
4149

42-
def events = @events ||= event_filter.entries.joins(:dates).order(dates: {start_at: :asc})
50+
def event_filter
51+
@event_filter ||= Events::Filter::AgendaList.new(nil, params)
52+
end
4353

44-
def event_filter = @event_filter ||= Events::Filter::AgendaList.new(nil, params)
54+
def events = @events ||= event_filter.entries.joins(:dates).order(dates: {start_at: :asc})
4555

4656
def group = @group ||= params[:group_id].present? ? Group.find(params[:group_id]) : nil
4757

48-
def event = @event ||= events.find(params[:event_id])
58+
def event = @event ||= event_filter.entries.find(params[:event_id])
4959
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright (c) 2026, Schweizer Alpenclub SAC. This file is part of
4+
# hitobito and licensed under the Affero General Public License version 3
5+
# or later. See the COPYING file at the top-level directory or at
6+
# https://github.com/hitobito/hitobito_sac_cas.
7+
8+
module Events::Filter
9+
class ApplicationOpen < Base
10+
self.permitted_args = [:value]
11+
12+
def apply(scope)
13+
scope.application_period_open
14+
end
15+
16+
def blank?
17+
args[:value].to_i != 1
18+
end
19+
end
20+
end

app/helpers/agenda_helper.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright (c) 2026, Schweizer Alpen-Club. This file is part of
4+
# hitobito_sac_cas and licensed under the Affero General Public License version 3
5+
# or later. See the COPYING file at the top-level directory or at
6+
# https://github.com/hitobito/hitobito_sac_cas.
7+
8+
module AgendaHelper
9+
def show_places_available_filter?(group)
10+
group.events.future.where(
11+
state: %w[published ready closed canceled],
12+
type: Event::Tour.sti_name,
13+
display_booking_info: true
14+
).exists?
15+
end
16+
end
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2026, Hitobito AG. This file is part of
2+
// hitobito and licensed under the Affero General Public License version 3
3+
// or later. See the COPYING file at the top-level directory or at
4+
// https://github.com/hitobito/hitobito_sac_cas.
5+
6+
import { Controller } from "@hotwired/stimulus";
7+
8+
/*
9+
Resets every filter field in the form to its true blank state (not the
10+
server-rendered value the page loaded with) and re-submits, so the results
11+
turbo frame refreshes with an unfiltered list. A field can opt out of
12+
blanking via data-reset-value, e.g. the since date field resets to today
13+
rather than to empty (see agenda/_date_filters).
14+
15+
data-controller="agenda-filters"
16+
data-action="click->agenda-filters#reset"
17+
*/
18+
export default class extends Controller {
19+
reset() {
20+
this.element.querySelectorAll('input[type="text"]').forEach((input) => {
21+
input.value = input.dataset.resetValue || "";
22+
});
23+
this.element.querySelectorAll('input[type="radio"]').forEach((radio) => {
24+
radio.checked = radio.value === "0";
25+
});
26+
this.element.querySelectorAll("select[data-controller~='tom-select']").forEach((select) => {
27+
if (select.tomselect) select.tomselect.clear();
28+
});
29+
this.element.requestSubmit();
30+
}
31+
}

app/javascript/packs/agenda.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@
22
// hitobito and licensed under the Affero General Public License version 3
33
// or later. See the COPYING file at the top-level directory or at
44
// https://github.com/hitobito/hitobito.
5-
6-
import '../stylesheets/agenda';
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2026, Hitobito AG. This file is part of
2+
// hitobito and licensed under the Affero General Public License version 3
3+
// or later. See the COPYING file at the top-level directory or at
4+
// https://github.com/hitobito/hitobito_sac_cas.
5+
6+
// Bootstrap
7+
@import "bootstrap/scss/functions";
8+
@import "bootstrap/scss/variables";
9+
@import "bootstrap/scss/maps";
10+
@import "bootstrap/scss/utilities";
11+
@import "bootstrap/scss/bootstrap";
12+
13+
14+
// Dependencies
15+
@import "~@fortawesome/fontawesome-free/css/all";
16+
@import "~tom-select/dist/css/tom-select.bootstrap5.css";
17+
18+
// Custom Stylesheets
19+
@import "../stylesheets/agenda";
20+
@import "../../../../hitobito/app/javascript/stylesheets/hitobito/modules/ui-datepicker";
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-# Copyright (c) 2026, Hitobito AG. This file is part of
2+
-# hitobito and licensed under the Affero General Public License version 3
3+
-# or later. See the COPYING file at the top-level directory or at
4+
-# https://github.com/hitobito/hitobito.
5+
6+
.d-flex.flex-column
7+
= f.fields_for(:application_open) do |ff|
8+
%span.form-label= t(".application_open")
9+
.d-flex.gap-3
10+
%label.form-check-label
11+
= ff.radio_button(:value, 1, checked: event_filter.chain.dig(:application_open, :value) == "1", class: "form-check-input")
12+
= t("global.yes")
13+
%label.form-check-label
14+
= ff.radio_button(:value, 0, checked: event_filter.chain.dig(:application_open, :value) != "1", class: "form-check-input")
15+
= t("global.no")
16+
17+
- if show_places_available_filter?(group)
18+
.d-flex.flex-column
19+
= f.fields_for(:places_available) do |ff|
20+
%span.form-label= t(".places_available")
21+
.d-flex.gap-3
22+
%label.form-check-label
23+
= ff.radio_button(:value, 1, checked: event_filter.chain.dig(:places_available, :value) == "1", class: "form-check-input")
24+
= t("global.yes")
25+
%label.form-check-label
26+
= ff.radio_button(:value, 0, checked: event_filter.chain.dig(:places_available, :value) != "1", class: "form-check-input")
27+
= t("global.no")
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-# Copyright (c) 2026, Hitobito AG. This file is part of
2+
-# hitobito and licensed under the Affero General Public License version 3
3+
-# or later. See the COPYING file at the top-level directory or at
4+
-# https://github.com/hitobito/hitobito.
5+
6+
.d-flex.flex-column
7+
= f.fields_for(:date_range) do |ff|
8+
= ff.label(:since, t(".since"), class: "form-label")
9+
= ff.text_field(:since, value: event_filter.chain.dig(:date_range, :since),
10+
class: "date form-control form-control-sm",
11+
data: {reset_value: I18n.l(Time.zone.today.to_date)})
12+
13+
.d-flex.flex-column
14+
= f.fields_for(:date_range) do |ff|
15+
= ff.label(:until, t(".until"), class: "form-label")
16+
= ff.text_field(:until, value: event_filter.chain.dig(:date_range, :until), class: "date form-control form-control-sm")

app/views/agenda/_event_card.html.haml

Lines changed: 0 additions & 38 deletions
This file was deleted.

app/views/agenda/_list.html.haml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-# Copyright (c) 2026, Hitobito AG. This file is part of
2+
-# hitobito and licensed under the Affero General Public License version 3
3+
-# or later. See the COPYING file at the top-level directory or at
4+
-# https://github.com/hitobito/hitobito.
5+
6+
= turbo_frame_tag(:agenda_events_list, target: :_top) do
7+
.alert.alert-info= t(".tours_found", count: events.count)
8+
9+
- events.each do |event|
10+
%div
11+
%div= event.id
12+
%div= event.name
13+
%div= I18n.l(event.start_at)
14+
%div= event.total_duration_days
15+
16+
- if event.display_booking_info?
17+
%div= "#{event.participant_count}/#{event.maximum_participants}"
18+
19+
%div= event.contact
20+
%div= link_to t(".show_details"), agenda_show_path(group, event)
21+
22+
- if event.is_a?(Event::Tour)
23+
%div= event.activities.join(", ")
24+
%div= event.technical_requirements.join(", ")
25+
%div= event.fitness_requirement
26+
%div= event.target_groups.join(", ")
27+
%div= "#{event.ascent} / #{event.descent} / #{event.duration_in_hours}"

0 commit comments

Comments
 (0)