Skip to content

Commit

Permalink
WIP: add guests_kids seralized column
Browse files Browse the repository at this point in the history
  • Loading branch information
kigster committed May 20, 2024
1 parent cd1ce29 commit 949c9db
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 100 deletions.
9 changes: 5 additions & 4 deletions app/controllers/ticket_requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def download

CSV.open(csv_file.path, 'w',
write_headers: true,
headers: TicketRequest.csv_header) do |csv|
headers: TicketRequest.csv_header) do |csv|
TicketRequest.for_csv(@event).each do |row|
csv << row
end
Expand Down Expand Up @@ -154,11 +154,11 @@ def update
# Allow ticket request to edit guests and nothing else
ticket_request_params = permitted_params[:ticket_request]

guests = (Array(ticket_request_params[:guest_list]) || [])
guests = (Array(ticket_request_params[:adult_guest_list]) || [])
.flatten.map(&:presence)
.compact

ticket_request_params.delete(:guest_list)
ticket_request_params.delete(:adult_guest_list)
ticket_request_params[:guests] = guests

if @ticket_request.valid? && @ticket_request.update!(ticket_request_params)
Expand Down Expand Up @@ -286,7 +286,8 @@ def permitted_params
:agrees_to_terms,
:early_arrival_passes,
:late_departure_passes,
{ guest_list: [] }
{ adult_guest_list: [] },
{ kid_guest_list: [] },
]
)
.to_hash
Expand Down
68 changes: 51 additions & 17 deletions app/models/ticket_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# donation :decimal(8, 2) default(0.0)
# early_arrival_passes :integer default(0), not null
# guests :text
# guests_kids :text
# kids :integer default(0), not null
# late_departure_passes :integer default(0), not null
# needs_assistance :boolean default(FALSE), not null
Expand All @@ -45,7 +46,7 @@ class << self
# @description
# This method returns a two-dimensional array. The first row is the header row,
# and then for each ticket request we return the primary user with the ticket request info,
# followed by one row per guest.
# followed by one row per kid.
def for_csv(event)
table = []

Expand All @@ -64,24 +65,31 @@ def for_csv(event)

table << row

ticket_request.guests.each do |guest|
age_string = guest.include?(',') ? guest.gsub(/.*,/, '').strip : ''
first, last, = guest.split(/[\s,]+/)
ticket_request.guests&.each do |guest|
next if guest.blank?

guest.include?(',') ? guest.gsub(/.*,/, '').strip : ''
first, last, = guest.split(/\s+/)
email = guest.include?('<') ? guest.gsub(/.*</, '').gsub(/>.*/, '') : ''
table << ["#{first} #{last}", email, 'Adult', '']
end

next if "#{first} #{last}" == ticket_request.user.name || email == ticket_request.user.email
ticket_request.guests_kids&.each do |kid|
next if kid.blank?

kids_age = age_string.empty? ? '' : kids_age(age_string)
age_string = kid.include?(',') ? kid.gsub(/.*,/, '').strip : ''
first, last, = kid.split(/\s+/)
kids_age = age_string.empty? ? '' : kids_age(age_string)

table << ["#{first} #{last}", email, 'Yes', kids_age]
table << ["#{first} #{last}", '', 'Kid', kids_age]
end
end

table
end

def csv_header
['Name', 'Email', 'Guest?', 'Kids Age', *csv_columns.map(&:titleize)]
['Name', 'Email', 'Guest Type', 'Kids Age', *csv_columns.map(&:titleize)]
end

def csv_columns
Expand Down Expand Up @@ -164,14 +172,16 @@ def kids_age(string)

# Serialize guest emails as an array in a text field.
serialize :guests, coder: Psych, type: Array
# Serialize kids names and ages as an array in a text field.
serialize :guests_kids, coder: Psych, type: Array

attr_accessible :user_id, :adults, :kids, :cabins, :needs_assistance,
:notes, :status, :special_price, :event_id,
:user_attributes, :user, :donation, :role, :role_explanation,
:car_camping, :car_camping_explanation, :previous_contribution,
:address_line1, :address_line2, :city, :state, :zip_code,
:country_code, :admin_notes, :agrees_to_terms,
:early_arrival_passes, :late_departure_passes, :guests
:early_arrival_passes, :late_departure_passes, :guests, :guests_kids

normalize_attributes :notes, :role_explanation, :previous_contribution,
:admin_notes, :car_camping_explanation
Expand All @@ -190,14 +200,16 @@ def kids_age(string)
validates :kids, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :cabins, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :role, presence: true, inclusion: { in: ROLES.keys }
validates :role_explanation, presence: { if: -> { role == ROLE_OTHER } }, length: { maximum: 400 }
validates :role_explanation, presence: { if: -> { role == ROLE_OTHER } }, length: { maximum: 200 }
validates :previous_contribution, length: { maximum: 250 }
validates :notes, length: { maximum: 500 }
validates :guests, length: { maximum: 10 }
validates :special_price, allow_nil: true, numericality: { greater_than_or_equal_to: 0 }
validates :donation, numericality: { greater_than_or_equal_to: 0 }
validates :agrees_to_terms, presence: true

# Validate that the total number of adult + kid guests is less that the total_tickets - 1 (for the ticket request user)
validate :maximum_guests

scope :completed, -> { where(status: STATUS_COMPLETED) }
scope :pending, -> { where(status: STATUS_PENDING) }
scope :awaiting_payment, -> { where(status: STATUS_AWAITING_PAYMENT) }
Expand Down Expand Up @@ -319,23 +331,31 @@ def total_tickets
adults + kids
end

def guest_count
def guest_expected_count
total_tickets - 1
end

def guests_specified
Array(guests).size
def adult_guests_count
Array(guests || []).size || 0
end

def kid_guests_count
Array(guests_kids || []).size || 0
end

def guest_list
def adult_guest_list
[].tap do |guest_list|
guest_list << user.name_and_email
guests.each { |guest| guest_list << guest }
end.compact
end

def kid_guest_list
guests_kids.compact
end

def all_guests_specified?
guests_specified >= guest_count
adult_guests_count + kid_guests_count == guests_expected_count
end

def country_name
Expand All @@ -356,6 +376,20 @@ def set_defaults

# Remove empty guests
# Note that guests are serialized as an array field.
self.guests = Array(guests).map { |guest| guest&.strip }.select(&:present?).compact
self.guests = Array(guests).map { |guest| guest&.strip }.select(&:present?).compact
self.guests_kids = Array(guests_kids).map { |guest| guest&.strip }.select(&:present?).compact
end

def maximum_guests
if adults.present? && guests.present? && adult_guests_count > (adults - 1)
# adult guests must be less that adult tickets - 1 (for the request owner)
errors.add(:base, 'You provided more adult guests than tickets')
false
elsif kids.present? && kids.positive? && guests_kids.present? && kid_guests_count > kids
errors.add(:base, 'You provided more kid guests than kid tickets')
false
else
true
end
end
end
2 changes: 1 addition & 1 deletion app/views/events/guest_list.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= render partial: 'shared/nav_event', locals: { event: @event, active_tab: { guest_list: 'active' } }
= render partial: 'shared/nav_event', locals: { event: @event, active_tab: { adult_guest_list: 'active' } }

.card
.card-header.bg-primary-subtle
Expand Down
2 changes: 1 addition & 1 deletion app/views/events/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
%td.p-1.text-end.optional.align-content-center
= number_with_delimiter(event.ticket_requests.count)
%td.p-1.text-end.align-content-center
= number_with_delimiter(event.ticket_requests.sum(&:guest_count))
= number_with_delimiter(event.ticket_requests.sum(&:guests_expected_count))
%td.p-1.text-end.optional.align-content-center
= number_to_currency(event.ticket_requests.completed.sum(&:cost))
%td.p-1.text-end.optional.align-content-center
Expand Down
129 changes: 73 additions & 56 deletions app/views/ticket_requests/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -31,41 +31,60 @@
- else
= form_for @ticket_request,
url: { controller: :ticket_requests, action: form_action_name }, data: { "turbo-target": "_top", turbo: false } do |f|
= f.hidden_field :event_id, value: @event.id
- if is_update
%hr
%h4 Guests
%p
Please list everyone in your party including the kids. We do not (currently) send automated emails to any of the guests you specify.
%p
For adults — please list their full name, and an email address as shown in the below example.
.content-fluid
.row
.col-lg-6.col-xl-6.col-md-12.col-sm-12
.container-fluid
.row
.col-12
= f.hidden_field :event_id, value: @event.id
- if is_update
%a{name: "guests"}/
%p
.control-group
%h4 Guests
%p
Please list everyone in your party including the kids. We do not (currently) send automated emails to any of the guests you specify.
%p
For adults — please list their full name, and an email address as shown in the below example.
%p
DJs should write their DJ Name, as well as the regular name and email address.
- list_finalized = (@event.start_time - Time.current) < ::Event::GUEST_LIST_FINAL_WITHIN
- if list_finalized
%span.text-error
Guest list has already been finalized. If you need to update your guests, please email
= mail_to '[email protected]'
%br
- else
%h4 Adult Guests
%h5 Examples:
%ul
%li DJ Carl Cox (as himself) &lt;[email protected]&gt;
%li John Digweed &lt;[email protected]&gt;
- total_guests = @ticket_request.guest_count
- adult_guests = @ticket_request.adults - 1
- adult_guests.times do |guest_id|
- next if @ticket_request.guests[guest_id] == "#{@ticket_request.user.name} <#{@ticket_request.user.email}>"
= f.label "Adult Guest #{guest_id + 1}"
= f.text_field :guest_list, readonly: list_finalized, multiple: true, value: Array(@ticket_request.guests[0...adult_guests])[guest_id], style: 'width: 80%'

- if @ticket_request.kids.positive?
.col-lg-6.col-xl-6.col-md-12.col-sm-12
.row
- if list_finalized
%span.text-error
Guest list has already been finalized. If you need to update your guests, please email
= mail_to '[email protected]'
%br
- else
.col-sm-12.col-md-12.col-lg-6.col-xl-6
%h5 Adults
%p.text-success
%strong Adult Name Examples
%ul
%li DJ Carl Cox (as himself) &lt;[email protected]&gt;
%li John Digweed &lt;[email protected]&gt;
- total_guests = @ticket_request.guests_expected_count
- adult_guests = @ticket_request.adults
- adult_guests.times do |guest_id|
= f.label "Adult Guest #{guest_id + 1}"
- default_value = guest_id == 0 ? @ticket_request.user.name_and_email : ''
= f.text_field :adult_guest_list, readonly: list_finalized, multiple: true, value: @ticket_request.guests[guest_id] || default_value, style: 'width: 80%'

- if @ticket_request.kids.positive?
.col-sm-12.col-md-12.col-lg-6.col-xl-6
%h5 Kids
%p.text-success
%strong Kid Name Examples
%ul
%li Taylor Swift, 12
%li Jonah Hill, 8
%li Channing Tatum, 5
.small Please enter "Full Name, Age" eg "Justin Bieber, 12"
- kid_guests = @ticket_request.kids
- kid_guests.times do |guest_id|
= f.label "Kid Number #{guest_id + 1}"
= f.text_field :kid_guest_list, readonly: list_finalized, multiple: true, value: @ticket_request.guests_kids[guest_id], style: 'width: 80%'

%h4 Kid Guests
%h5 Examples:
Expand All @@ -77,35 +96,33 @@
= f.label "Kid Guest #{guest_id + 1}"
= f.text_field :guest_list, readonly: list_finalized, multiple: true, value: Array(@ticket_request.guests[(adult_guests)...total_guests])[guest_id], style: 'width: 80%'

%hr
%h4 How are you contributing to the event?
.content-fluid
%h5 How are you contributing to the event?
.row
.col-lg-6.col-xl-6.col-md-12.col-sm-12
.input-group-large
%fieldset
%p
= f.label :role_volunteer do
= f.label :role_volunteer, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_VOLUNTEER,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_VOLUNTEER] }
= TicketRequest::ROLES[TicketRequest::ROLE_VOLUNTEER]
= f.label :role_contributor, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_CONTRIBUTOR,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_CONTRIBUTOR] }
= TicketRequest::ROLES[TicketRequest::ROLE_CONTRIBUTOR]
= f.label :role_coordinator, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_COORDINATOR,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_COORDINATOR] }
= TicketRequest::ROLES[TicketRequest::ROLE_COORDINATOR]
= f.label :role_uber_coordinator, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_UBER_COORDINATOR,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_UBER_COORDINATOR] }
= TicketRequest::ROLES[TicketRequest::ROLE_UBER_COORDINATOR]
= f.label :role_other, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_OTHER,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_OTHER] }
= TicketRequest::ROLES[TicketRequest::ROLE_OTHER]
= f.label :role_volunteer, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_VOLUNTEER,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_VOLUNTEER] }
= TicketRequest::ROLES[TicketRequest::ROLE_VOLUNTEER]
= f.label :role_contributor, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_CONTRIBUTOR,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_CONTRIBUTOR] }
= TicketRequest::ROLES[TicketRequest::ROLE_CONTRIBUTOR]
= f.label :role_coordinator, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_COORDINATOR,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_COORDINATOR] }
= TicketRequest::ROLES[TicketRequest::ROLE_COORDINATOR]
= f.label :role_uber_coordinator, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_UBER_COORDINATOR,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_UBER_COORDINATOR] }
= TicketRequest::ROLES[TicketRequest::ROLE_UBER_COORDINATOR]
= f.label :role_other, class: 'radio inline' do
= f.radio_button :role, TicketRequest::ROLE_OTHER,
data: { 'max-tickets' => TicketRequest::TICKET_LIMITS[TicketRequest::ROLE_OTHER] }
= TicketRequest::ROLES[TicketRequest::ROLE_OTHER]

.col-lg-6.col-xl-6.col-md-12.col-sm-12.align-content-md-center
%p.muted.role-explanation{ class: TicketRequest::ROLE_VOLUNTEER }
Expand Down
8 changes: 4 additions & 4 deletions app/views/ticket_requests/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -199,16 +199,16 @@
%strong
= @ticket_request.notes

- if @ticket_request.guest_count > 0
- if @ticket_request.guests_expected_count > 0
%tr
%td
%td
%hr
%tr.align-middle
%td.text-end.small.p-2.px-4.text-nowrap= 'Guest'.pluralize(@ticket_request.guest_count) + ':'
%td.text-end.small.p-2.px-4.text-nowrap= 'Guest'.pluralize(@ticket_request.guests_expected_count) + ':'
%td
%em
- @ticket_request.guest_count.times do |guest_id|
- @ticket_request.guests_expected_count.times do |guest_id|
.text-nowrap.small
= Array(@ticket_request.guests)[guest_id] || 'Unspecified'
%br
Expand Down Expand Up @@ -250,7 +250,7 @@
= link_to event_ticket_requests_path(@event), class: 'btn btn-success btn-round btn-sm' do
All Requests

- if @event.admin?(current_user) || @ticket_request.guest_count > 0
- if @event.admin?(current_user) || @ticket_request.guests_expected_count > 0
= link_to edit_event_ticket_request_path(@event, @ticket_request), class: 'btn btn-primary btn-round btn-sm mx-0' do
= @event.admin?(current_user) ? 'Edit Ticket Request' : 'Edit Guests'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddGuestKidsToTicketRequests < ActiveRecord::Migration[7.1]
def change
add_column :ticket_requests, :guests_kids, :text
end
end
Loading

0 comments on commit 949c9db

Please sign in to comment.