From 2c976d40a40bffa839051684d56bbc90e22913c9 Mon Sep 17 00:00:00 2001 From: Godwin Date: Sun, 14 Aug 2016 22:59:43 -0700 Subject: [PATCH] Reworked housing page --- app/assets/javascripts/housing.js | 93 ++++++++ app/assets/stylesheets/_application.scss | 199 +++++++++++++++++- app/controllers/application_controller.rb | 2 +- app/controllers/conferences_controller.rb | 122 ++++++----- app/helpers/application_helper.rb | 80 +++++-- .../conferences/admin/_hosts_table.html.haml | 11 + .../conferences/admin/_housing.html.haml | 52 +---- .../admin/_select_guest_table.html.haml | 46 ++++ app/views/conferences/stats.xlsx.haml | 2 +- config/locales/en.yml | 11 +- 10 files changed, 500 insertions(+), 118 deletions(-) create mode 100644 app/views/conferences/admin/_hosts_table.html.haml create mode 100644 app/views/conferences/admin/_select_guest_table.html.haml diff --git a/app/assets/javascripts/housing.js b/app/assets/javascripts/housing.js index bad38dd..34c2f05 100644 --- a/app/assets/javascripts/housing.js +++ b/app/assets/javascripts/housing.js @@ -1,4 +1,97 @@ (function() { + function closeGuestSelector() { + document.getElementById('guest-selector').classList.remove('open'); + } + function _post(form, params, f) { + var request = new XMLHttpRequest(); + request.onreadystatechange = function() { + if (request.readyState == 4) { + if (request.status == 200) { + f(request.responseText); + } + } + } + request.open('POST', form.getAttribute('action'), true); + request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); + params['authenticity_token'] = form.querySelector('[name="authenticity_token"]').value; + var data = []; + for (var key in params) { + //data.push(key + '=' + encodeURI(params[key])); + data.push(key + '=' + params[key]); + } + request.send(data.join('&')); + } + + function initHostTable(table) { + forEachElement('.select-guest', function(button) { + button.addEventListener('click', function(event) { + event.preventDefault(); + document.getElementById('guest-selector').classList.add('open'); + var table = document.getElementById('table'); + table.classList.add('loading'); + _post( + document.getElementById('housing-table-form'), + { + host: button.getAttribute('data-host'), + space: button.getAttribute('data-space'), + button: 'get-guest-list' + }, + function (response) { + var table = document.getElementById('table'); + table.innerHTML = response; + table.classList.remove('loading'); + forEachElement('tr.selectable', function(row) { + row.addEventListener('click', function(event) { + var table = document.getElementById('housing-table'); + table.classList.add('loading'); + closeGuestSelector(); + _post( + document.getElementById('guest-list-table'), + { + host: row.getAttribute('data-host'), + guest: row.getAttribute('data-guest'), + space: row.getAttribute('data-space'), + button: 'set-guest' + }, + function(response) { + table.innerHTML = response; + table.classList.remove('loading'); + initHostTable(table); + } + ) + }); + }, table); + } + ); + }); + }); + + forEachElement('.remove-guest', function(button) { + button.addEventListener('click', function(event) { + event.preventDefault(); + var table = document.getElementById('housing-table'); + table.classList.add('loading'); + _post( + document.getElementById('housing-table-form'), + { + guest: button.getAttribute('data-guest'), + button: 'remove-guest' + }, + function (response) { + table.innerHTML = response; + table.classList.remove('loading'); + initHostTable(table); + } + ); + }); + }); + } + initHostTable(document.getElementById('housing-table')); + document.getElementById('guest-selector').addEventListener('click', function(event) { + if (event.target.id == 'guest-selector') { + closeGuestSelector(); + } + }); function closeOnTop() { document.documentElement.removeAttribute('data-ontop'); document.getElementById('guest_id').value = ''; diff --git a/app/assets/stylesheets/_application.scss b/app/assets/stylesheets/_application.scss index 524e9f0..49f3be0 100644 --- a/app/assets/stylesheets/_application.scss +++ b/app/assets/stylesheets/_application.scss @@ -1490,6 +1490,43 @@ ul.warnings li, } #admin-housing { + .guests-housed { + margin-bottom: 1em; + text-align: right; + + h5 { + display: inline-block; + margin: 0; + padding-right: 0.5em; + } + + .data { + display: inline-block; + font-size: 1.125em; + } + } + + #housing-table { + @include _(transition, opacity 1s ease-in-out); + + &.loading { + @include _(opacity, 0.5); + pointer-events: none; + } + + tr.host { + th { + vertical-align: top; + } + + .address { + margin-top: 1em; + text-align: right; + @include font-family(primary); + } + } + } + .host-table { tr.place-guest { td { @@ -1498,6 +1535,14 @@ ul.warnings li, &:hover { background-color: $colour-1; } + + &.full { + background-color: #E8E8E8; + + &:hover { + background-color: #CCC; + } + } } a { @@ -1512,6 +1557,7 @@ ul.warnings li, } } + .remove-guest, button, .button { float: right; } @@ -1535,13 +1581,15 @@ ul.warnings li, top: 0; background-color: $white; border: 0.1em solid #CCC; - padding: 0.25em 0.75em; + padding: 0.25em 0.75em 0.25em 1.5em; margin: 0; - list-style: none; + list-style-type: square; @include default-box-shadow(top, 2); + z-index: 10; } li { + white-space: nowrap; margin: 0; } @@ -1554,12 +1602,19 @@ ul.warnings li, } #guest-selector { + display: none; position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba($black, 0.5); + cursor: pointer; + z-index: 1000; + + &.open { + display: block; + } .guest-dlg { position: absolute; @@ -1569,12 +1624,144 @@ ul.warnings li, left: 0; background-color: $white; width: 80%; - max-width: 25em; + margin: auto; + padding: 1em; + height: 80%; + cursor: default; @include default-box-shadow(top, 2); + + h3 { + margin: 0 0 1em; + } } } } +@include keyframes(whiten) { + to { background-color: $white; } +} + +#table { + position: relative; + overflow: auto; + height: 80%; + height: calc(100% - 4em); + background-color: $white; + @include _(transition, background-color 250ms ease-in-out); + + &.loading { + background-color: #CCC; + @include _(animation, whiten ease-in-out 1s infinite alternate both); + + .host-field, table, .legend { + display: none; + } + } + + table { + min-width: 100em; + } + + h4 { + margin: 0; + + &.inline { + display: inline-block; + padding-right: 0.5em; + } + } + + .plain-value { + font-size: 1.2em; + } + + blockquote { + margin-top: 0; + font-size: 0.85em; + + > :first-child { + margin-top: 0; + } + } + + tr.selectable { + cursor: pointer; + + &:hover { + th { + background-color: $colour-2; + } + } + + &.other-host, &.other-space, &.bad-match { + td, th { + opacity: 0.5; + } + } + + &.selected-space, &.other-space { + td { + background-color: lighten($colour-5, 35); + } + + th { + background-color: $colour-5; + } + } + + &.other-host { + td { + background-color: lighten($colour-1, 40%); + } + + th { + background-color: $colour-1; + } + } + + &:hover { + td { + opacity: 1; + background-color: lighten($colour-2, 25%); + } + } + } + + .legend ul { + @include _-(display, flex); + list-style: none; + padding: 0; + + li { + @include _(flex, 1); + text-align: center; + margin-bottom: 0.5em; + padding: 0.125em 0.5em; + margin: 0.1em; + border: 0.1em solid #EEE; + background-color: #F8F8F8; + @include font-family(secondary); + + &.other-host, &.other-space, &.bad-match { + opacity: 0.5; + } + + &.selected-space, &.other-space { + background-color: $colour-5; + } + + &.other-host { + background-color: $colour-1; + } + } + } + + .p { + max-height: 4em; + overflow: auto; + } +} + #admin-housing { #hosts { background-color: $white; @@ -1862,9 +2049,9 @@ table.schedule { } .event-dlg { - @include _-(flex, 0); - position: relative; - z-index: 1000; + @include _-(flex, 0); + position: relative; + z-index: 1000; background-color: $white; text-align: left; padding: 2em 2em 0.5em; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a0f9bac..73f9b7d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,7 +8,7 @@ class ApplicationController < LinguaFrancaApplicationController # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. - protect_from_forgery with: :exception, :except => [:do_confirm, :js_error] + protect_from_forgery with: :exception, :except => [:do_confirm, :js_error, :admin_update] before_filter :capture_page_info diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 1a07efd..4dadb48 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -138,7 +138,7 @@ class ConferencesController < ApplicationController } when :questions # create the companion's user account and send a registration link unless they have already registered - generate_confirmation(User.create(email: params[:companion]), register_path(@this_conference.slug)) unless User.find_by_email(params[:companion]) + generate_confirmation(User.create(email: params[:companion]), register_path(@this_conference.slug)) if params[:companion].present? && User.find_by_email(params[:companion]).nil? @registration.housing = params[:housing] @registration.arrival = params[:arrival] @@ -225,7 +225,18 @@ class ConferencesController < ApplicationController # prepare the form case @register_template when :questions - @registration.housing_data ||= { } + # see if someone else has asked to be your companion + if @registration.housing_data.blank? + ConferenceRegistration.where( + conference_id: @this_conference.id, can_provide_housing: [nil, false] + ).where.not(housing_data: nil).each do | r | + @registration.housing_data = { + companions: [ r.user.email ] + } if r.housing_data['companions'].present? && r.housing_data['companions'].include?(current_user.email) + end + + @registration.housing_data ||= { } + end @page_title = 'articles.conference_registration.headings.Registration_Info' when :payment @page_title = 'articles.conference_registration.headings.Payment' @@ -337,7 +348,7 @@ class ConferencesController < ApplicationController ], column_types: { name: :bold, - #date: :date, + date: :datetime, arrival: [:date, :day], departure: [:date, :day], registration_fees_paid: :money @@ -483,11 +494,15 @@ class ConferencesController < ApplicationController @housing_data[id][:space][s.to_sym] = size end end + + @guests_housed = 0 + @guests.each do | guest_id, guest | data = guest.housing_data || {} @hosts_affected_by_guests[guest_id] ||= [] if data['host'] + @guests_housed += 1 host_id = (data['host'].present? ? data['host'].to_i : nil) host = host_id.present? ? @hosts[host_id] : nil @@ -506,21 +521,14 @@ class ConferencesController < ApplicationController @housing_data[host_id][:guests][space][guest_id] = { guest: guest } - # make sure the host isn't overbooked - space_available = ((host_data['space'] || {})[space.to_s] || 0).to_i - if @housing_data[host_id][:guests][space].size > space_available - @housing_data[host_id][:warnings] ||= {} - @housing_data[host_id][:warnings][:space] ||= {} - @housing_data[host_id][:warnings][:space][space] ||= [] - @housing_data[host_id][:warnings][:space][space] << :overbooked - end - @housing_data[host_id][:guest_data] ||= {} @housing_data[host_id][:guest_data][guest_id] = { warnings: {}, errors: {} } + @housing_data[host_id][:guest_data][guest_id][:warnings][:dates] = {} unless view_context.available_dates_match?(host, guest) + if (guest.housing == 'house' && space == :tent) || (guest.housing == 'tent' && (space == :bed_space || space == :floor_space)) - @housing_data[host_id][:guest_data][guest_id][:warnings][:space] = { actual: space.to_s, expected: guest.housing} + @housing_data[host_id][:guest_data][guest_id][:warnings][:space] = { actual: (view_context._"forms.labels.generic.#{space.to_s}"), expected: (view_context._"articles.conference_registration.questions.housing.#{guest.housing}")} end companions = data['companions'] || [] @@ -534,14 +542,10 @@ class ConferencesController < ApplicationController if reg.present? && @guests[reg.id].present? housing_data = reg.housing_data || {} companion_host = housing_data['host'].present? ? housing_data['host'].to_i : nil - if companion_host.blank? - @hosts_affected_by_guests[guest_id] << companion_host - if companion_host != host_id && reg.housing.present? && reg.housing != 'none' - # set this as an error if the guest has selected only one other to stay with, but if they have requested to stay with more, make this only a warning - status = companions.size > 1 ? :warnings : :errors - @housing_data[host_id][:guest_data][guest_id][status][:companions] ||= [] - @housing_data[host_id][:guest_data][guest_id][status][:companions] << { name: reg.user.name, id: reg.id } - end + @hosts_affected_by_guests[guest_id] << companion_host + if companion_host != host_id && reg.housing.present? && reg.housing != 'none' + # set this as an error if the guest has selected only one other to stay with, but if they have requested to stay with more, make this only a warning + @housing_data[host_id][:guest_data][guest_id][:warnings][:companions] = { name: "#{reg.user.name}".html_safe, id: reg.id } end end end @@ -554,6 +558,24 @@ class ConferencesController < ApplicationController end end end + + @hosts.each do | id, host | + host_data = host.housing_data + + @hosts[id].housing_data['space'].each do | space, size | + # make sure the host isn't overbooked + space = space.to_sym + space_available = (size || 0).to_i + @housing_data[id][:warnings] ||= {} + @housing_data[id][:warnings][:space] ||= {} + @housing_data[id][:warnings][:space][space] ||= [] + + if @housing_data[id][:guests][space].size > space_available + @housing_data[id][:warnings][:space][space] << :overbooked + end + end + end + return @hosts_affected_by_guests end @@ -607,41 +629,41 @@ class ConferencesController < ApplicationController return redirect_to administration_step_path(@this_conference.slug, :payment) end when 'housing' - space = params[:button].split(':')[0] - host_id = params[:button].split(':')[1].to_i - guest_id = params[:guest_id].to_i - - get_housing_data - # modify the guest data - @guests[guest_id].housing_data ||= {} - @guests[guest_id].housing_data['space'] = space - @guests[guest_id].housing_data['host'] = host_id - @guests[guest_id].save! - if request.xhr? + if params[:button] == 'get-guest-list' + # get_housing_data + analyze_housing + return render partial: 'conferences/admin/select_guest_table', locals: { host: @hosts[params['host'].to_i], space: params['space'] } + elsif params[:button] == 'set-guest' + guest = ConferenceRegistration.where( + id: params[:guest].to_i, + conference_id: @this_conference.id + ).limit(1).first + + guest.housing_data ||= {} + guest.housing_data['space'] = params[:space] + guest.housing_data['host'] = params[:host].to_i + guest.save! + analyze_housing - # get the hosts that need updating - affected_hosts = {} - affected_hosts[host_id] = @hosts[host_id] - if params['affected-hosts'].present? - params['affected-hosts'].split(',').each do | id | - affected_hosts[id.to_i] = @hosts[id.to_i] - end - end - @hosts_affected_by_guests[guest_id].each do | id | - affected_hosts[id] ||= @hosts[id] - end + return render partial: 'conferences/admin/hosts_table' + elsif params[:button] == 'remove-guest' + guest = ConferenceRegistration.where( + id: params[:guest].to_i, + conference_id: @this_conference.id + ).limit(1).first + + guest.housing_data ||= {} + guest.housing_data.delete('space') + guest.housing_data.delete('host') + guest.save! + + analyze_housing - json = { hosts: {}, affected_hosts: @hosts_affected_by_guests } - puts @hosts_affected_by_guests[guest_id].to_json.to_s - affected_hosts.each do | id, host | - json[:hosts][id] = view_context.host_guests_widget(host) - end - return render json: json + return render partial: 'conferences/admin/hosts_table' end - return redirect_to administration_step_path(@this_conference.slug, :housing) when 'broadcast' @hide_description = true @subject = params[:subject] diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index edf981e..9eae995 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1003,20 +1003,20 @@ module ApplicationHelper @housing_data[id][:guest_data][guest_id][:errors].each do | error, value | if value.is_a?(Array) value.each do | v | - status_html += _("errors.housing.space.#{error.to_s}", vars: {value: v}) + status_html += content_tag(:li, _("errors.messages.housing.space.#{error.to_s}", vars: v)) end else - status_html += _("errors.housing.space.#{error.to_s}", vars: {value: value }) + status_html += content_tag(:li, _("errors.messages.housing.space.#{error.to_s}", vars: value)) end end @housing_data[id][:guest_data][guest_id][:warnings].each do | error, value | if value.is_a?(Array) value.each do | v | - status_html += _("warnings.housing.space.#{error.to_s}", v) + status_html += content_tag(:li, _("warnings.messages.housing.space.#{error.to_s}", v)) end else - status_html += _("warnings.housing.space.#{error.to_s}", vars: value) + status_html += content_tag(:li, _("warnings.messages.housing.space.#{error.to_s}", vars: value)) end end @@ -1028,23 +1028,26 @@ module ApplicationHelper (content_tag :td, guest[:guest].user.name) + (content_tag :td do (guest[:guest].city + - (button_tag :remove, class: [:small, :delete])).html_safe + (content_tag :a, (_'actions.workshops.Remove'), href: '#', class: 'remove-guest', data: { guest: guest_id })).html_safe end) + (content_tag :td, status_html.html_safe, class: [:state, status_html.present? ? :unhappy : :happy]) end + end - for i in guests.size..(@housing_data[id][:space][area] || 0) - guest_rows += content_tag :tr, class: 'empty-space' do - (content_tag :td, '', colspan: 2) + - (content_tag :td) - end + space_size = (@housing_data[id][:space][area] || 0) + + # add empty rows to represent empty guest spots + for i in guests.size...space_size + guest_rows += content_tag :tr, class: 'empty-space' do + (content_tag :td, ' '.html_safe, colspan: 2) + + (content_tag :td) end end status_html = '' if @housing_data[id][:warnings].present? && @housing_data[id][:warnings][:space].present? && @housing_data[id][:warnings][:space][area].present? @housing_data[id][:warnings][:space][area].each do | w | - status_html += content_tag(:li, _("warnings.housing.space.#{w.to_s}")) + status_html += content_tag(:li, _("warnings.messages.housing.space.#{w.to_s}")) end end if status_html.present? @@ -1057,7 +1060,7 @@ module ApplicationHelper end html += guest_rows html += content_tag :tr, class: 'place-guest' do - content_tag :td, colspan: 3 do + content_tag :td, class: guests.size >= space_size ? 'full' : nil, colspan: 3 do content_tag :a, (_'forms.actions.generic.place_guest'), class: 'select-guest', href: '#', data: { host: id, space: area } end end @@ -1065,6 +1068,43 @@ module ApplicationHelper content_tag :table, html.html_safe, class: 'host-table' end + + def get_housing_match(host, guest, space) + housing_data = guest.housing_data || [] + + if housing_data['host'].present? + if housing_data['host'] == host.id + return space == housing_data['space'] ? :selected_space : :other_space + end + + return :other_host + end + + if space_matches?(space, guest.housing) && available_dates_match?(host, guest) + return :good_match + end + + return :bad_match + end + + def space_matches?(host_space, guest_space) + return false unless host_space.present? && guest_space.present? + + if host_space.to_s == 'bed_space' || host_space.to_s == 'floor_space' + return guest_space.to_s == 'house' + end + + return host_space.to_s == 'tent_space' && guest_space.to_s == 'tent' + end + + def available_dates_match?(host, guest) + if host.housing_data['availability'][0] <= guest.arrival && + host.housing_data['availability'][1] >= guest.departure + return true + end + + return false + end def host_guests_widget(registration) html = '' @@ -1460,6 +1500,22 @@ module ApplicationHelper return html.html_safe end + def companion(registration) + if registration.housing_data.present? && registration.housing_data['companions'].present? && registration.housing_data['companions'].first.present? + companion_user = User.find_by_email(registration.housing_data['companions'].first) + + if companion_user.present? + cr = ConferenceRegistration.where(user_id: companion_user.id).order(created_at: :desc).limit(1).first + + if cr.present? && ((cr.steps_completed || []).include? 'questions') + return companion_user + end + end + return :unregistered + end + return nil + end + def comment(comment) add_inline_script :time add_js_translation('datetime.distance_in_words') diff --git a/app/views/conferences/admin/_hosts_table.html.haml b/app/views/conferences/admin/_hosts_table.html.haml new file mode 100644 index 0000000..021380d --- /dev/null +++ b/app/views/conferences/admin/_hosts_table.html.haml @@ -0,0 +1,11 @@ +.guests-housed + %h5 Guests Housed: + .data="#{@guests_housed} / #{@guests.size}" + +%table.hosts.admin-edit + - @hosts.each do | id, registration | + %tr.host + %th + .name=registration.user.name + .address=registration.housing_data['address'] + %td.inner-table{colspan: 2}=host_guests_table(registration) diff --git a/app/views/conferences/admin/_housing.html.haml b/app/views/conferences/admin/_housing.html.haml index e2a455d..6b2442e 100644 --- a/app/views/conferences/admin/_housing.html.haml +++ b/app/views/conferences/admin/_housing.html.haml @@ -1,47 +1,7 @@ - add_inline_script :housing -= form_tag administration_update_path(@this_conference.slug, :housing), id: :hosts, class: 'on-top-target' do - = hidden_field_tag :guest_id - .on-top-controls - = button_tag :close, type: :button, class: ['on-top-close'] - %ul - - @hosts.each do | id, registration | - - if registration.user.present? - - widget_data = host_guests_widget(registration) - %li{id: "host-#{id}", class: widget_data[:class]} - %h4=registration.user.name - .email=registration.user.email - .address=registration.housing_data['address'] - .guests=widget_data[:html] -#guests - %h4=_'articles.admin.housing.headings.guests', :t - %ul.guests - - @guests.each do | id, registration | - - if registration.user.present? - %li.guest{id: "guest-#{id}", data: { id: id, 'affected-hosts': @hosts_affected_by_guests[id].join(',') }} - %h4= registration.user.name - .city=registration.city - .on-top-only.details - = data_set(:h4, 'articles.admin.housing.headings.email') do - = registration.user.email - = data_set(:h4, 'articles.admin.housing.headings.housing') do - = registration.housing - - if registration.arrival.present? - = data_set(:h4, 'articles.admin.housing.headings.arrival_departure') do - = date_span(registration.arrival.to_date, registration.departure.to_date) - - if (registration.housing_data || {})['companions'].present? - = data_set(:h4, 'articles.admin.housing.headings.companion') do - - companion = User.find_by_email(registration.housing_data['companions'].first) - - if companion - = "#{companion.firstname} (#{companion.email})" - - else - = registration.housing_data['companions'].first - = _'articles.admin.housing.headings.unregistered' - - if registration.allergies.present? - = data_set(:h4, 'articles.admin.housing.headings.allergies') do - = registration.allergies - - if registration.other.present? - = data_set(:h4, 'articles.admin.housing.headings.other') do - = registration.other - = button_tag :set_host, type: :button, class: [:small, 'set-host', 'not-on-top'] - - += form_tag administration_update_path(@this_conference.slug, :housing), id: 'housing-table-form' do + #housing-table= render partial: 'conferences/admin/hosts_table' +#guest-selector + = form_tag administration_update_path(@this_conference.slug, :housing), class: 'guest-dlg', id: 'guest-list-table' do + %h3 Select a Guest + #table diff --git a/app/views/conferences/admin/_select_guest_table.html.haml b/app/views/conferences/admin/_select_guest_table.html.haml new file mode 100644 index 0000000..adc8097 --- /dev/null +++ b/app/views/conferences/admin/_select_guest_table.html.haml @@ -0,0 +1,46 @@ += hidden_field_tag :host, host.id +.host-field + %h4.inline=_'forms.labels.generic.name' + %span.plain-value= host.user.name +.host-field + %h4.inline=_'articles.conference_registration.headings.host.availability' + %span.plain-value= date_span(host.housing_data['availability'][0].to_date, host.housing_data['availability'][1].to_date) +- if host.housing_data['considerations'].present? + .host-field + %h4.inline=_'articles.conference_registration.headings.host.considerations' + %span.plain-value= (host.housing_data['considerations'].map { | consideration | _"articles.conference_registration.host.considerations.#{consideration}" }).join(', ') +- if sanitize(host.housing_data['notes'], tags: []).present? + .host-field + %h4=_'articles.conference_registration.headings.host.notes' + %blockquote= host.housing_data['notes'].html_safe +%table.guests.admin-edit + %tr + %th.corner + %th=_'forms.labels.generic.city' + %th=_'forms.labels.generic.housing' + %th=_'articles.admin.housing.headings.arrival_departure' + %th=_'forms.labels.generic.companion' + %th=_'forms.labels.generic.food' + %th=_'forms.labels.generic.allergies' + %th=_'forms.labels.generic.other' + - @guests.each do | id, registration | + %tr.selectable{class: get_housing_match(host, registration, space).to_s.gsub('_', '-'), data: {host: host.id, guest: id, space: space}} + %th=registration.user.name + %td=registration.city + %td=_"articles.conference_registration.questions.housing.#{registration.housing}" + %td=date_span(registration.arrival.to_date, registration.departure.to_date) + - companion = companion(registration) + %td=companion.present? ? (companion.is_a?(User) ? companion.name : (_"articles.conference_registration.terms.registration_status.#{companion}")) : '' + %td=_"articles.conference_registration.questions.food.#{registration.food}" + %td=registration.allergies + %td + .p=registration.other + +.legend + %h4 Legend + %ul + %li.good-match Good Match + %li.bad-match Poor Match + %li.selected-space Also in this space + %li.other-space Also with this host + %li.other-host Already hosted diff --git a/app/views/conferences/stats.xlsx.haml b/app/views/conferences/stats.xlsx.haml index 5353eb0..7a3d277 100644 --- a/app/views/conferences/stats.xlsx.haml +++ b/app/views/conferences/stats.xlsx.haml @@ -15,7 +15,7 @@ - format bg_color: '333333' - format 'td', font_name: 'Calibri', fg_color: '333333' - format 'th', font_name: 'Calibri', b: true, bg_color: '333333', fg_color: 'ffffff' - - format 'td.date', num_fmt: 22, font_name: 'Courier New', sz: 10, fg_color: '333333' + - format 'td.datetime', num_fmt: 22, font_name: 'Courier New', sz: 10, fg_color: '333333' - format 'td.date.day', num_fmt: 14, font_name: 'Courier New', sz: 10, fg_color: '333333' - format 'td.money', num_fmt: 2, font_name: 'Courier New', sz: 10, fg_color: '333333' - format 'td.bold', font_name: 'Calibri', fg_color: '333333', b: true diff --git a/config/locales/en.yml b/config/locales/en.yml index 770529a..208d157 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -167,6 +167,9 @@ en: empty: 'Please enter an address' space: empty: 'Please select a space' + housing: + space: + companions: This host wishes to be housed with %{name} template: body: 'There were problems with the following fields:' header: @@ -177,7 +180,10 @@ en: location_corrected: Your location was corrected from "%{original}" to "%{corrected}". If this doesn't reflect your intended location, you can change this again in the contact info step. housing: space: - overbooked: Overbooked + overbooked: This space is overbooked + companions: This guest wishes to be housed with %{name} + space: This guest wishes to be housed in a %{expected} + dates: This guest's arrival or departure dates conflict with the host's availability dates helpers: select: prompt: Please select @@ -887,12 +893,13 @@ en: description: On this page you can schedule workshops and publish your schedule to the front page. no_locations_warning: Before you can schedule workshops, you must first add locations. housing: - description: The housing tool can be used to help you set up visitors that have requested to be housed with a host. + description: The housing tool can be used to help you set up visitors that have requested to be housed with a host. When you see an error icon beside a host's space or a guest's details, hover over it to see warnings. Ideally you should only check marks which will indicate that all hosts and guests are happy. headings: hosts: Hosts guests: Guests email: Email housing: Preference + arrival_departure: In City locations: description: Locations are used to schedule workshops, events, and meals. Once your schedule is published, users will be able to see the name and address and be given a link to a map so that they can find their way. headings: