Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<% if model.registration_form_enabled? %>
<%= action_authorized_link_to(
:join_waitlist,
join_waitlist_meeting_registration_path(model),
class: button_classes
) do %>
<%= icon(icon_name) %>
<%= i18n_join_waitlist_text %>
<% end %>
<% else %>
<% unless options[:hide_modal] %>
<%= render :registration_modal %>
<% end %>
<%= action_authorized_button_to(
:join_waitlist,
content_tag(:span, "#{icon(icon_name)} #{i18n_join_waitlist_text}".html_safe),
"#",
class: button_classes,
data: { "dialog-open": current_user.present? ? "meeting-registration-confirm-#{model.id}" : "loginModal" },
resource: model
) %>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

module Decidim
module Meetings
# This cell renders the button to join a waitlist.
class JoinWaitlistButtonCell < Decidim::ViewModel
include MeetingCellsHelper

def show
return unless model.waitlist_enabled? && !model.has_available_slots? && model.can_be_joined_by?(current_user)
return if model.has_registration_for?(current_user)

render
end

private

def current_component
model.component
end

def button_classes
"button button__sm button__transparent-secondary w-full"
end

def i18n_join_waitlist_text
return if !model.waitlist_enabled? && model.has_available_slots?

I18n.t("add_to_waitlist", scope: "decidim.meetings.meetings.show")
end

def icon_name
"list-ordered"
end

def registration_form
@registration_form ||= Decidim::Meetings::JoinMeetingForm.new
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def attributes
available_slots: form.available_slots,
reserved_slots: form.reserved_slots,
registration_terms: form.registration_terms,
waitlist_enabled: form.waitlist_enabled,
customize_registration_email: form.customize_registration_email
}
extra_params.merge!(registration_email_custom_content: form.registration_email_custom_content) if form.customize_registration_email
Expand Down
57 changes: 57 additions & 0 deletions decidim-meetings/app/commands/decidim/meetings/join_waitlist.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module Decidim
module Meetings
# This command is executed when the user joins a meeting waitlist.
class JoinWaitlist < Decidim::Command
delegate :current_user, to: :form

def initialize(meeting, form)
@meeting = meeting
@user_group = Decidim::UserGroup.find_by(id: form.user_group_id)
@form = form
end

def call
return broadcast(:invalid) unless can_join_waitlist?
return broadcast(:invalid_form) unless form.valid?

meeting.with_lock do
create_waitlist_entry
send_waitlist_notification
end

broadcast(:ok)
end

private

attr_reader :meeting, :user_group, :form

def can_join_waitlist?
meeting.waitlist_enabled? &&
!meeting.registrations.exists?(user: current_user) &&
!meeting.has_available_slots?
end

def create_waitlist_entry
@registration = Decidim::Meetings::Registration.create!(
meeting:,
user: current_user,
user_group:,
public_participation: form.public_participation,
status: :waiting_list
)
end

def send_waitlist_notification
Decidim::EventsManager.publish(
event: "decidim.events.meetings.meeting_waitlist_added",
event_class: Decidim::Meetings::MeetingWaitlistNotificationEvent,
resource: meeting,
affected_users: [current_user]
)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ def create
end
end

def join_waitlist
enforce_permission_to(:join_waitlist, :meeting, meeting:)

@form = JoinMeetingForm.from_params(params).with_context(current_user:)

JoinWaitlist.call(meeting, @form) do
on(:ok) do
flash[:notice] = I18n.t("registrations.waitlist.success", scope: "decidim.meetings")
redirect_after_path
end

on(:invalid) do
flash.now[:alert] = I18n.t("registrations.waitlist.invalid", scope: "decidim.meetings")
redirect_after_path
end
end
end

def destroy
enforce_permission_to(:leave, :meeting, meeting:)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class MeetingRegistrationsForm < Decidim::Form
attribute :customize_registration_email, Boolean
attribute :available_slots, Integer
attribute :reserved_slots, Integer
attribute :waitlist_enabled, :boolean, default: false

translatable_attribute :registration_terms, Decidim::Attributes::RichText
translatable_attribute :registration_email_custom_content, Decidim::Attributes::RichText
Expand All @@ -22,6 +23,7 @@ class MeetingRegistrationsForm < Decidim::Form
validates :available_slots, :reserved_slots, presence: true, if: ->(form) { form.registrations_enabled? }
validates :available_slots, numericality: { greater_than_or_equal_to: 0 }, if: ->(form) { form.registrations_enabled? && form.available_slots.present? }
validates :reserved_slots, numericality: { greater_than_or_equal_to: 0 }, if: ->(form) { form.registrations_enabled? }
validates :waitlist_enabled, inclusion: { in: [true, false] }
validates :reserved_slots, numericality: { less_than_or_equal_to: :available_slots }, if: lambda { |form|
form.registrations_enabled? &&
form.reserved_slots.present? &&
Expand Down
4 changes: 4 additions & 0 deletions decidim-meetings/app/models/decidim/meetings/registration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ class Registration < Meetings::ApplicationRecord
validates :code, uniqueness: { allow_blank: true, scope: :meeting }
validates :code, presence: true, on: :create

enum status: { registered: "registered", waitlisted: "waitlisted" }, _prefix: true
Comment thread Fixed
Comment thread Fixed

before_validation :generate_code, on: :create

scope :public_participant, -> { where(decidim_user_group_id: nil, public_participation: true) }
scope :registered, -> { where(status: :registered) }
scope :waiting_list, -> { where(status: :waiting_list).order(:created_at) }

def self.user_collection(user)
where(decidim_user_id: user.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<%= form.number_field :reserved_slots, help_text: t(".reserved_slots_help") %>
</div>

<div class="row column">
<%= form.check_box :waitlist_enabled, help_text: t(".waitlist_enabled_help") %>
</div>

<div class="row column">
<%= form.check_box :customize_registration_email %>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
</section>
<% end %>

<% if meeting.waitlist_enabled? && !meeting.has_available_slots? && meeting.can_be_joined_by?(current_user) %>
<section class="layout-aside__section layout-aside__buttons layout-aside__ctas-buttons" data-sticky-buttons>
<%= cell "decidim/meetings/join_waitlist_button", meeting, hide_modal: local_assigns[:hide_modal] %>
</section>
<% end %>

<% if (meeting.closed? && meeting.closing_visible?) || (registration.present? && registration.meeting.component.settings.registration_code_enabled) || (meeting.services.any?) %>
<section class="layout-aside__section layout-aside__buttons">
<% if meeting.closed? && meeting.closing_visible? %>
Expand Down
3 changes: 3 additions & 0 deletions decidim-meetings/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ en:
reserved_slots_help: Leave it to 0 if you do not have reserved slots.
reserved_slots_less_than: Must be less than or equal to %{count}
title: Registrations
waitlist_enabled: Waitlist enabled
waitlist_enabled_help: If enabled, the user will be able to join the waitlist when the available slots are full.
update:
invalid: There was a problem saving the registration settings.
success: Meeting registrations settings successfully saved.
Expand Down Expand Up @@ -592,6 +594,7 @@ en:
cancel: Cancel
confirm: Confirm
show:
add_to_waitlist: Add to waitlist
attendees: Attendees count
contributions: Contributions count
join: Register
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class AddWaitlistEnabledToDecidimMeetings < ActiveRecord::Migration[7.0]
def change
add_column :decidim_meetings_meetings, :waitlist_enabled, :boolean, default: false, null: false
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

class AddStatusToRegistrationsToDecidimMeetingsRegistrations < ActiveRecord::Migration[7.0]
def change
add_column :decidim_meetings_registrations, :status, :string, default: "registered", null: false
add_index :decidim_meetings_registrations, :status
end
end
1 change: 1 addition & 0 deletions decidim-meetings/lib/decidim/meetings/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Engine < ::Rails::Engine
get :decline_invitation
get :join, action: :show
post :answer
post :join_waitlist
end
end
resources :versions, only: [:show]
Expand Down