From 30024d86b6793965090a4334a0e06c81c1fda8a3 Mon Sep 17 00:00:00 2001 From: Godwin Date: Fri, 12 Aug 2016 22:53:55 -0700 Subject: [PATCH] Fixed bugs, restyled pages, and added instructions for admin pages --- app/assets/stylesheets/_application.scss | 8 +- .../stylesheets/bumbleberry-settings.json | 2 +- app/controllers/application_controller.rb | 11 +- app/controllers/conferences_controller.rb | 55 ++-- app/helpers/application_helper.rb | 28 +- .../locale_not_available.html.haml | 2 +- .../conferences/_administration.html.haml | 1 + app/views/conferences/admin/_events.html.haml | 78 +++--- .../conferences/admin/_locations.html.haml | 48 ++-- app/views/conferences/admin/_meals.html.haml | 62 +++-- .../conferences/admin/_schedule.html.haml | 262 ++++++++--------- app/views/conferences/stats.xlsx.haml | 10 +- app/views/shared/_footer.html.haml | 2 +- config/initializers/i18n.rb | 263 ------------------ config/locales/en.yml | 31 +++ 15 files changed, 347 insertions(+), 516 deletions(-) diff --git a/app/assets/stylesheets/_application.scss b/app/assets/stylesheets/_application.scss index 078d449..2df08d1 100644 --- a/app/assets/stylesheets/_application.scss +++ b/app/assets/stylesheets/_application.scss @@ -123,6 +123,10 @@ table, .table { tbody th { width: 0.1rem; } + + &.admin-edit { + width: 100%; + } } .table { @@ -496,7 +500,7 @@ input { } .input-field-help { - margin: 0.5em 1em 0; + margin: 0.5em 1em; line-height: 1.3333em; font-size: 1.125em; } @@ -760,6 +764,7 @@ form { #main .columns td.form, #main .columns .table-td.form { border: 0; + width: 1px; form { margin: 0; @@ -768,6 +773,7 @@ form { button { display: block; width: 100%; + white-space: nowrap; + button { margin-top: 0.5em; diff --git a/app/assets/stylesheets/bumbleberry-settings.json b/app/assets/stylesheets/bumbleberry-settings.json index a8ba7fd..04a7c8b 100644 --- a/app/assets/stylesheets/bumbleberry-settings.json +++ b/app/assets/stylesheets/bumbleberry-settings.json @@ -6,7 +6,7 @@ }, "development": { "and_chr": ["51"], - "chrome": ["51"], + "chrome": ["52"], "edge": ["13"], "firefox": ["44"], "ie": ["11"], diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 770a4f1..a0f9bac 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -201,7 +201,7 @@ class ApplicationController < LinguaFrancaApplicationController params[:_original_action] = params[:action] params[:action] = 'error-locale-not-available' @page_title = 'page_titles.404.Locale_Not_Available' - @main_title_vars = { vars: { language: view_context.language(locale) } } + @main_title_vars = { vars: { language: view_context.language_name(locale) } } @main_title = 'error.locale_not_available.title' render 'application/locale_not_available', status: 404 end @@ -507,7 +507,7 @@ class ApplicationController < LinguaFrancaApplicationController if @schedule[day].present? && @schedule[day][:times].present? && @schedule[day][:times][block['time'].to_f].present? @schedule[day][:times][block['time'].to_f][:item][:workshops][workshop.event_location_id] = { workshop: workshop, status: { errors: [], warnings: [], conflict_score: nil } } - @schedule[day][:locations][workshop.event_location_id] ||= workshop.event_location + @schedule[day][:locations][workshop.event_location_id] ||= workshop.event_location if workshop.event_location.present? end end end @@ -613,18 +613,19 @@ class ApplicationController < LinguaFrancaApplicationController end end + location = workshop_i.event_location || EventLocation.new needs = JSON.parse(workshop_i.needs || '[]').map &:to_sym - amenities = JSON.parse(workshop_i.event_location.amenities || '[]').map &:to_sym + amenities = JSON.parse(location.amenities || '[]').map &:to_sym needs.each do | need | @schedule[day][:times][time][:item][:workshops][ids[i]][:status][:errors] << { name: :need_not_available, need: need, - location: workshop_i.event_location, + location: location, workshop: workshop_i, i18nVars: { need: need.to_s, - location: workshop_i.event_location.title, + location: location.title, workshop_title: workshop_i.title } } unless amenities.include? need diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 881521c..cc0edf8 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -267,6 +267,7 @@ class ConferencesController < ApplicationController when :policy @page_title = 'articles.conference_registration.headings.Policy_Agreement' when :administration + @warnings << flash[:error] if flash[:error].present? @admin_step = params[:admin_step] || 'edit' return do_404 unless view_context.valid_admin_steps.include?(@admin_step.to_sym) @page_title = 'articles.conference_registration.headings.Administration' @@ -336,7 +337,7 @@ class ConferencesController < ApplicationController ], column_types: { name: :bold, - date: :date, + #date: :date, arrival: [:date, :day], departure: [:date, :day], registration_fees_paid: :money @@ -360,7 +361,6 @@ class ConferencesController < ApplicationController }, data: [] } - #@registrations.sort_by! { |a, b| a.title.downcase <=> b.title.downcase } @registrations.each do | r | user = r.user_id ? User.where(id: r.user_id).first : nil if user.present? @@ -378,14 +378,15 @@ class ConferencesController < ApplicationController end end steps = r.steps_completed || [] + @excel_data[:data] << { name: user.firstname || '', email: user.email || '', status: (view_context._"articles.conference_registration.terms.registration_status.#{(steps.include? 'questions') ? 'registered' : ((steps.include? 'contact_info') ? 'preregistered' : 'unregistered')}"), - date: r.created_at ? r.created_at.strftime("%F %T") : '', + date: r.created_at,# ? r.created_at.strftime("%F %T") : '', city: r.city || '', - preferred_language: user.locale.present? ? (view_context.language user.locale) : '', - languages: ((r.languages || []).map { |x| view_context.language x }).join(', ').to_s, + preferred_language: user.locale.present? ? (view_context.language_name user.locale) : '', + languages: ((r.languages || []).map { |x| view_context.language_name x }).join(', ').to_s, arrival: r.arrival ? r.arrival.strftime("%F %T") : '', departure: r.departure ? r.departure.strftime("%F %T") : '', housing: r.housing || '', @@ -619,6 +620,7 @@ class ConferencesController < ApplicationController end return redirect_to administration_step_path(@this_conference.slug, :housing) when 'broadcast' + @hide_description = true @subject = params[:subject] @body = params[:body] @send_to = params[:send_to] @@ -660,11 +662,16 @@ class ConferencesController < ApplicationController return render 'conferences/register' when 'save' location = EventLocation.find_by! id: params[:id].to_i, conference_id: @this_conference.id - location.title = params[:title] - location.address = params[:address] - location.amenities = (params[:needs] || {}).keys.to_json - location.space = params[:space] - location.save! + empty_param = get_empty(params, [:title, :address, :space]) + if empty_param.present? + flash[:error] = (view_context._"errors.messages.fields.#{empty_param.to_s}.empty") + else + location.title = params[:title] + location.address = params[:address] + location.amenities = (params[:needs] || {}).keys.to_json + location.space = params[:space] + location.save! + end return redirect_to administration_step_path(@this_conference.slug, :locations) when 'cancel' return redirect_to administration_step_path(@this_conference.slug, :locations) @@ -673,13 +680,18 @@ class ConferencesController < ApplicationController location.destroy return redirect_to administration_step_path(@this_conference.slug, :locations) when 'create' - EventLocation.create( - conference_id: @this_conference.id, - title: params[:title], - address: params[:address], - amenities: (params[:needs] || {}).keys.to_json, - space: params[:space] - ) + empty_param = get_empty(params, [:title, :address, :space]) + if empty_param.present? + flash[:error] = (view_context._"errors.messages.fields.#{empty_param.to_s}.empty") + else + EventLocation.create( + conference_id: @this_conference.id, + title: params[:title], + address: params[:address], + amenities: (params[:needs] || {}).keys.to_json, + space: params[:space] + ) + end return redirect_to administration_step_path(@this_conference.slug, :locations) end when 'meals' @@ -1444,6 +1456,15 @@ class ConferencesController < ApplicationController UserMailer.conference_registration_payment_received(@conference, data, registration).deliver end + def get_empty(hash, keys) + keys = [keys] unless keys.is_a?(Array) + keys.each do | key | + puts " ===== #{key} = #{hash[key]} ===== " + return key unless hash[key].present? + end + return nil + end + def PayPal! Paypal::Express::Request.new( username: @this_conference.paypal_username, diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c7dda52..4d2f4ad 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -618,6 +618,11 @@ module ApplicationHelper return hash.length > 1 ? _("geography.formats.#{hash.keys.join('_')}", locale: locale, vars: hash) : hash.values.first end + def location_link(location) + return '' unless location.present? && location.address.present? + content_tag(:a, (_!location.address), href: "http://www.google.com/maps/place/#{location.latitude},#{location.longitude}") + end + def same_city?(location1, location2) return false unless location1.present? && location2.present? @@ -651,7 +656,7 @@ module ApplicationHelper link_to "#{title}".html_safe, link, :class => classes end - def language(locale, original_language = false) + def language_name(locale, original_language = false) args = {} args[:locale] = locale if original_language _("languages.#{locale}", args) @@ -828,7 +833,11 @@ module ApplicationHelper end def location_name(id) - location = EventLocation.find(id) + begin + location = EventLocation.find(id) + rescue + return '' + end return '' unless location.present? return location.title end @@ -1193,6 +1202,9 @@ module ApplicationHelper end elsif options[:label] != false html += label_tag id, (_"forms.labels.generic.#{name}") + elsif options[:type] == :select + # add an empty label so that the drop down button will still appear + html += label_tag id, '' end input_options = { id: id, @@ -1302,18 +1314,26 @@ module ApplicationHelper values = values.present? ? values.map(&:to_s) : [] unless is_single boxes = boxes.map(&:to_s) end + + # convert the required value into a pure boolean + required = !!options[:required] + boxes.each do | box | checked = (is_single ? values.present? : values.include?(box)) values -= [box] if checked && !is_single id = nil if options[:radiobuttons].present? id = unique_id("#{name.to_s}_#{box}") - boxes_html += radio_button_tag(name, box, checked, id: id) + boxes_html += radio_button_tag(name, box, checked, id: id, required: required) else _name = (is_single ? name : "#{name.to_s}[#{box}]") id = unique_id(_name) - boxes_html += check_box_tag(_name, 1, checked, data: { toggles: options[:toggles] }.compact, id: id) + boxes_html += check_box_tag(_name, 1, checked, data: { toggles: options[:toggles] }.compact, id: id, required: required) end + + # we only need the required attribute on one element + required = false + if is_single label = _(label_key.to_s) elsif box.is_a?(Integer) diff --git a/app/views/application/locale_not_available.html.haml b/app/views/application/locale_not_available.html.haml index 31d9e6f..f9beb45 100644 --- a/app/views/application/locale_not_available.html.haml +++ b/app/views/application/locale_not_available.html.haml @@ -5,7 +5,7 @@ %ul.locales - @alt_lang_urls.each do |locale, url| %li - - locale_translation = language(locale, true) + - locale_translation = language_name(locale, true) %a.button{href: url, lang: locale} =_'translate.content.change_locale', "Read in #{locale_translation}", vars: {language: locale_translation}, locale: locale %h2= _'error.locale_not_available.volunteer.title' diff --git a/app/views/conferences/_administration.html.haml b/app/views/conferences/_administration.html.haml index 03a90b0..62c36c5 100644 --- a/app/views/conferences/_administration.html.haml +++ b/app/views/conferences/_administration.html.haml @@ -2,4 +2,5 @@ = admin_menu = columns(medium: 9, large: 10) do %h3.subtitle=_("menu.submenu.admin.#{@admin_step.titlecase.gsub(/\s/, '_')}") + %p=(_"articles.admin.#{@admin_step.gsub(/\s/, '_')}.description", :p) unless @hide_description === true %div{id: "admin-#{@admin_step}"}= render "conferences/admin/#{@admin_step}" diff --git a/app/views/conferences/admin/_events.html.haml b/app/views/conferences/admin/_events.html.haml index dc89994..3b56457 100644 --- a/app/views/conferences/admin/_events.html.haml +++ b/app/views/conferences/admin/_events.html.haml @@ -1,36 +1,42 @@ -- if @events.present? - %ul.events.admin-blocks - - @events.each do | event | - %li - %h4.title=event.title - .details - = data_set(:h5, 'forms.labels.generic.event_location', class: :location) do - =event.event_location.present? ? event.event_location.title : '' - = data_set(:h5, 'forms.labels.generic.day', class: :day) do - = date(event.start_time.to_date, :weekday) - = data_set(:h5, 'forms.labels.generic.time', class: :time) do - = time(event.start_time, :short) - = data_set(:h5, 'forms.labels.generic.time_span', class: 'time-span') do - = hours(event.start_time, event.end_time) - = form_tag administration_update_path(@this_conference.slug, :events), class: [:actions, :fill] do - = hidden_field_tag :id, event.id - = button_with_confirmation :delete, (_'modals.admin.generic.delete.confirm', :p, vars: { title: event.title }), value: :delete, class: [:delete, :small] - = button_tag :edit, value: :edit, class: [:small] - -%h4=_"articles.admin.locations.headings.#{@event.id.present? ? 'edit' : 'add'}_event", :t -= form_tag administration_update_path(@this_conference.slug, :events) do - = hidden_field_tag :id, @event.id if @event.id.present? - = textfield :title, @event.title!, required: true, big: true, lang: @event.locale - = textarea :info, @event.info!, heading: 'articles.conference_registration.headings.admin.edit.info', help: 'articles.conference_registration.paragraphs.admin.edit.info', lang: @event.locale, edit_on: :focus - .flex-inputs - = location_select @event.event_location_id, small: true, stretch: true - = day_select @day, small: true, format: :weekday - = time_select @time, small: true - = length_select @length, small: true - - I18n.backend.enabled_locales.each do | locale | - - if locale.to_s != @event.locale.to_s - = textfield "title_translations[#{locale.to_s}]", @event._title(locale), big: true, heading: 'translate.pages.Locale_Translation', vars: { language: _("languages.#{locale}") }, label: 'forms.labels.generic.title', lang: locale - = textarea "info_translations[#{locale.to_s}]", @event._info(locale), lang: locale, label: 'forms.labels.generic.info', edit_on: :focus - .actions.next-prev - = button_tag :save, value: :save - = button_tag :cancel, value: :cancel, class: :subdued, formnovalidate: true if @event.id.present? +- if @this_conference.event_locations.blank? + .warning-info=_'articles.admin.events.no_locations_warning' +- else + - if @events.present? + %table.events.admin-edit + %tr + %th=_'forms.labels.generic.title' + %th=_'forms.labels.generic.event_location' + %th=_'forms.labels.generic.day' + %th=_'forms.labels.generic.time' + %th=_'forms.labels.generic.time_span' + %th.form + - @events.each do | event | + %tr + %th=event.title + %td=_!(event.event_location.present? ? event.event_location.title : '') + %td=date(event.start_time.to_date, :weekday) + %td=time(event.start_time, :short) + %td=hours(event.start_time, event.end_time) + %td.form + = form_tag administration_update_path(@this_conference.slug, :events) do + = hidden_field_tag :id, event.id + = button_tag :edit, value: :edit, class: :small + = button_with_confirmation :delete, (_'modals.admin.generic.delete.confirm', :p, vars: { title: event.title }), value: :delete, class: [:delete, :small] + + %h4=_"articles.admin.locations.headings.#{@event.id.present? ? 'edit' : 'add'}_event", :t + = form_tag administration_update_path(@this_conference.slug, :events) do + = hidden_field_tag :id, @event.id if @event.id.present? + = textfield :title, @event.title!, required: true, big: true, lang: @event.locale + = textarea :info, @event.info!, heading: 'articles.conference_registration.headings.admin.edit.info', help: 'articles.conference_registration.paragraphs.admin.events.info', lang: @event.locale, edit_on: :focus + .flex-inputs + = location_select @event.event_location_id, small: true, stretch: true + = day_select @day, small: true, format: :weekday + = time_select @time, small: true + = length_select @length, small: true + - I18n.backend.enabled_locales.each do | locale | + - if locale.to_s != @event.locale.to_s + = textfield "title_translations[#{locale.to_s}]", @event._title(locale), big: true, heading: 'translate.pages.Locale_Translation', vars: { language: _("languages.#{locale}") }, label: 'forms.labels.generic.title', lang: locale + = textarea "info_translations[#{locale.to_s}]", @event._info(locale), lang: locale, label: 'forms.labels.generic.info', edit_on: :focus + .actions.next-prev + = button_tag :save, value: :save + = button_tag :cancel, value: :cancel, class: :subdued, formnovalidate: true if @event.id.present? diff --git a/app/views/conferences/admin/_locations.html.haml b/app/views/conferences/admin/_locations.html.haml index d4b541e..ca891c2 100644 --- a/app/views/conferences/admin/_locations.html.haml +++ b/app/views/conferences/admin/_locations.html.haml @@ -1,32 +1,34 @@ - unless @location.present? - %ul.locations.admin-blocks - - @locations.each do | location | - %li - %h4.title=location.title - .details - = data_set(:h5, 'forms.labels.generic.address', class: :address) do - =location.address - = data_set(:h5, 'articles.workshops.headings.space', class: :space) do - = _"workshop.options.space.#{location.space}" - - amenities = location.amenities.present? ? JSON.parse(location.amenities) : [] - - if amenities.present? - = data_set(:h5, 'articles.admin.locations.headings.amenities', class: :amenities) do - %ul.amenities - - amenities.each do | amenity | - %li=_"workshop.options.needs.#{amenity}" - = form_tag administration_update_path(@this_conference.slug, :locations), class: [:actions, :fill] do - = hidden_field_tag :id, location.id - = button_tag :edit, value: :edit, class: :small - = button_with_confirmation :delete, (_'modals.admin.generic.delete.confirm', :p, vars: { title: location.title }), value: :delete, class: [:delete, :small] + - if @locations.present? + %table.locations.admin-edit + %tr + %th=_'forms.labels.generic.title' + %th=_'forms.labels.generic.address' + %th=_'articles.workshops.headings.space' + %th=_'articles.admin.locations.headings.amenities' + %th.form + - @locations.each do | location | + %tr + %th=_!(location.title || '') + %td=location_link location + %td=location.space.present? ? (_"workshop.options.space.#{location.space}") : '' + %td + - amenities = location.amenities.present? ? JSON.parse(location.amenities) : [] + =_!(amenities.collect { |amenity| _"workshop.options.needs.#{amenity}" }).join(', ') + %td.form + = form_tag administration_update_path(@this_conference.slug, :locations) do + = hidden_field_tag :id, location.id + = button_tag :edit, value: :edit, class: :small + = button_with_confirmation :delete, (_'modals.admin.generic.delete.confirm', :p, vars: { title: location.title }), value: :delete, class: [:delete, :small] %h4=_"articles.admin.locations.headings.#{@location.present? ? 'edit' : 'add'}_location", :t = form_tag administration_update_path(@this_conference.slug, :locations) do = hidden_field_tag :id, @location.id if @location.present? - = textfield :title, @location.present? ? @location.title : nil, required: true, big: true - = textfield :address, @location.present? ? @location.address : nil, required: true + = textfield :title, @location.present? ? @location.title : nil, required: true, big: true, help: 'articles.admin.locations.paragraphs.title' + = textfield :address, @location.present? ? @location.address : nil, required: true, help: 'articles.admin.locations.paragraphs.address' = columns(medium: 6) do - = radiobuttons :space, EventLocation.all_spaces, @location.present? ? @location.space : nil, 'workshop.options.space', vertical: true, heading: 'articles.workshops.headings.space' + = radiobuttons :space, EventLocation.all_spaces, @location.present? ? @location.space : nil, 'workshop.options.space', vertical: true, heading: 'articles.workshops.headings.space', required: true, help: 'articles.admin.locations.paragraphs.space' = columns(medium: 6) do - = checkboxes :needs, EventLocation.all_amenities, @location.present? ? JSON.parse(@location.amenities) : [], 'workshop.options.needs', vertical: true, heading: 'articles.admin.locations.headings.amenities' + = checkboxes :needs, EventLocation.all_amenities, @location.present? ? JSON.parse(@location.amenities) : [], 'workshop.options.needs', vertical: true, heading: 'articles.admin.locations.headings.amenities', help: 'articles.admin.locations.paragraphs.amenities' .actions.next-prev - if @location.present? = button_tag :save, value: :save diff --git a/app/views/conferences/admin/_meals.html.haml b/app/views/conferences/admin/_meals.html.haml index a3ea8c6..34f74dc 100644 --- a/app/views/conferences/admin/_meals.html.haml +++ b/app/views/conferences/admin/_meals.html.haml @@ -1,30 +1,34 @@ -- if @this_conference.meals.present? - %table.meals - %tr - %th=_'forms.labels.generic.title' - %th=_'forms.labels.generic.info' - %th=_'forms.labels.generic.event_location' - %th=_'forms.labels.generic.day' - %th=_'forms.labels.generic.time' - %th.form - - @meals.each do | time, meal | +- if @this_conference.event_locations.present? + - if @this_conference.meals.present? + %table.meals.admin-edit %tr - %th - =_!(meal['title'] || '') - %td=_!(meal['info'] || '') - %td=_!location_name(meal['location'].to_i) - %td=date(meal['day'], :weekday) - %td=time(meal['time'].to_f) - %td.form - = form_tag administration_update_path(@this_conference.slug, :meals) do - = hidden_field_tag :meal, time - = button_tag :delete, value: :delete, class: [:small, :delete] -= form_tag administration_update_path(@this_conference.slug, :meals) do - .flex-inputs - = location_select nil, small: true, stretch: true - = day_select nil, small: true, format: :weekday - = time_select nil, small: true - = textfield :title, nil, required: true, big: true - = textfield :info, nil - .actions.next-prev - = button_tag :add_meal, value: :add_meal \ No newline at end of file + %th=_'forms.labels.generic.title' + %th=_'forms.labels.generic.info' + %th=_'forms.labels.generic.event_location' + %th=_'forms.labels.generic.day' + %th=_'forms.labels.generic.time' + %th.form + - @meals.each do | time, meal | + %tr + %th + =_!(meal['title'] || '') + %td=_!(meal['info'] || '') + %td=_!location_name(meal['location'].to_i) + %td=date(meal['day'], :weekday) + %td=time(meal['time'].to_f) + %td.form + = form_tag administration_update_path(@this_conference.slug, :meals) do + = hidden_field_tag :meal, time + = button_tag :delete, value: :delete, class: [:small, :delete] + = form_tag administration_update_path(@this_conference.slug, :meals) do + %h4=_'articles.admin.locations.headings.add_meal', :t + .flex-inputs + = location_select nil, small: true, stretch: true + = day_select nil, small: true, format: :weekday + = time_select nil, small: true + = textfield :title, nil, required: true, big: true, help: 'articles.admin.locations.paragraphs.meal_title' + = textfield :info, nil, help: 'articles.admin.locations.paragraphs.meal_info' + .actions.next-prev + = button_tag :add_meal, value: :add_meal +- else + .warning-info=_'articles.admin.meals.no_locations_warning' \ No newline at end of file diff --git a/app/views/conferences/admin/_schedule.html.haml b/app/views/conferences/admin/_schedule.html.haml index 30670d4..31dcc64 100644 --- a/app/views/conferences/admin/_schedule.html.haml +++ b/app/views/conferences/admin/_schedule.html.haml @@ -1,134 +1,136 @@ - conference = @this_conference || @conference -- if @entire_page - = form_tag administration_update_path(conference.slug, :schedule) do - - if conference.workshop_schedule_published - %p=_'articles.conference_registration.paragraphs.admin.schedule.published', :p - .actions= button_tag :un_publish, value: :publish, class: :delete - - else - %p=_'articles.conference_registration.paragraphs.admin.schedule.un_published', :p - .actions= button_tag :publish, value: :publish - -#schedule-preview - - @schedule.each do | day, data | - %h4=date(day, :weekday) - %table.schedule{class: [data[:locations].present? ? 'has-locations' : 'no-locations', "locations-#{data[:locations].size}"]} - - if data[:locations].present? - %thead - %tr - %th.corner - - data[:locations].each do | id, location | - %th=location.title - %th.status - %tbody - - data[:times].each do | time, time_data | - %tr - - rowspan = (time_data[:length] * 2).to_i - %th=time(time) - - if time_data[:type] == :workshop - - if time_data[:item][:workshops].present? - - data[:locations].each do | id, location | - - if time_data[:item][:workshops][id].present? - - workshop = time_data[:item][:workshops][id][:workshop] - - status = time_data[:item][:workshops][id][:status] - - else - - workshop = status = nil - %td{class: [time_data[:type], workshop.present? ? :filled : nil], rowspan: rowspan} - - if workshop.present? - = link_to off_screen(workshop.title), view_workshop_path(@conference.slug, workshop.id), class: 'event-detail-link' - %template.event-details{data: { href: view_workshop_path(@conference.slug, workshop.id) }} - %h1.title=workshop.title - %p.address - = workshop.event_location.title + _!(': ') - %a{ href: "http://www.google.com/maps/place/#{workshop.event_location.latitude},#{workshop.event_location.longitude}" } - = workshop.event_location.address - .workshop-description= richtext workshop.info, 1 - .title=workshop.title - - if @can_edit - = form_tag administration_update_path(conference.slug, :schedule), class: 'js-xhr' do - .status - .conflict-score - %span.title Conflict Score: - %span.value="#{status[:conflict_score] * 100.0}%" - - if status[:errors].present? - .errors - - status[:errors].each do | error | - .error=_"errors.messages.schedule.#{error[:name].to_s}", vars: error[:i18nVars] - = hidden_field_tag :id, workshop.id - = button_tag :deschedule, value: :deschedule_workshop, class: [:delete, :small] - - elsif @can_edit +- if conference.event_locations.blank? && @entire_page + .warning-info=_'articles.admin.schedule.no_locations_warning' +- else + - if @entire_page + = form_tag administration_update_path(conference.slug, :schedule) do + - if conference.workshop_schedule_published + %p=_'articles.conference_registration.paragraphs.admin.schedule.published', :p + .actions= button_tag :un_publish, value: :publish, class: :delete + - else + %p=_'articles.conference_registration.paragraphs.admin.schedule.un_published', :p + .actions= button_tag :publish, value: :publish + + #schedule-preview + - @schedule.each do | day, data | + %h4=date(day, :weekday) + %table.schedule{class: [data[:locations].present? ? 'has-locations' : 'no-locations', "locations-#{data[:locations].size}"]} + - if data[:locations].present? + %thead + %tr + %th.corner + - data[:locations].each do | id, location | + %th=location.title + %th.status + %tbody + - data[:times].each do | time, time_data | + %tr + - rowspan = (time_data[:length] * 2).to_i + %th=time(time) + - if time_data[:type] == :workshop + - if time_data[:item][:workshops].present? + - data[:locations].each do | id, location | + - if time_data[:item][:workshops][id].present? + - workshop = time_data[:item][:workshops][id][:workshop] + - status = time_data[:item][:workshops][id][:status] + - else + - workshop = status = nil + %td{class: [time_data[:type], workshop.present? ? :filled : nil], rowspan: rowspan} + - if workshop.present? && workshop.event_location.present? + = link_to off_screen(workshop.title), view_workshop_path(@conference.slug, workshop.id), class: 'event-detail-link' + %template.event-details{data: { href: view_workshop_path(@conference.slug, workshop.id) }} + %h1.title=workshop.title + %p.address + = workshop.event_location.title + _!(': ') + = location_link workshop.event_location + .workshop-description= richtext workshop.info, 1 + .title=workshop.title + - if @can_edit + = form_tag administration_update_path(conference.slug, :schedule), class: 'js-xhr' do + .status + .conflict-score + %span.title Conflict Score: + %span.value="#{status[:conflict_score] * 100.0}%" + - if status[:errors].present? + .errors + - status[:errors].each do | error | + .error=_"errors.messages.schedule.#{error[:name].to_s}", vars: error[:i18nVars] + = hidden_field_tag :id, workshop.id + = button_tag :deschedule, value: :deschedule_workshop, class: [:delete, :small] + - elsif @can_edit + .title="Block #{time_data[:item][:block] + 1}" + - else + %td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1} + - if @can_edit .title="Block #{time_data[:item][:block] + 1}" - - else + %td.status{rowspan: rowspan} + - if time_data[:status].present? && time_data[:status][:errors].present? + %ul.errors + - time_data[:status][:errors].each do | error | + %li=error.to_json.to_s + - elsif time_data[:type] != :nil %td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1} - - if @can_edit - .title="Block #{time_data[:item][:block] + 1}" - %td.status{rowspan: rowspan} - - if time_data[:status].present? && time_data[:status][:errors].present? - %ul.errors - - time_data[:status][:errors].each do | error | - %li=error.to_json.to_s - - elsif time_data[:type] != :nil - %td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1} - - case time_data[:type] - - when :meal - %a.event-detail-link=off_screen(time_data[:item]['title']) - - location = EventLocation.find(time_data[:item]['location'].to_i) - %template.event-details - %h1.title=time_data[:item]['title'] - %p.address - = location.title + _!(': ') - %a{ href: "http://www.google.com/maps/place/#{location.latitude},#{location.longitude}" } - = location.address - .title= time_data[:item]['title'] - .location= location.title - - when :event - %a.event-detail-link=off_screen(time_data[:item][:title]) - %template.event-details - %h1.title=time_data[:item][:title] - %p.address - = time_data[:item].event_location.title + _!(': ') - %a{ href: "http://www.google.com/maps/place/#{time_data[:item].event_location.latitude},#{time_data[:item].event_location.longitude}" } - = time_data[:item].event_location.address - = richtext time_data[:item][:info], 1 - .title= time_data[:item][:title] - .location= time_data[:item].event_location.title - %td.status{rowspan: rowspan} -- if @entire_page - %ul.workshops-to-schedule - - @workshops.each do | workshop | - %li{id: "workshop-#{workshop.id}", class: workshop.block.present? ? 'booked' : 'not-booked'} - %h4.title= workshop.title - = form_tag administration_update_path(conference.slug, :schedule), class: 'js-xhr' do - .already-booked - .field-error='This block is already booked' - .workshop-description - .details - = data_set(:h5, 'articles.workshops.headings.interested_count') do - = workshop.interested_count - = data_set(:h5, 'articles.workshops.headings.facilitators') do - - facilitators = [] - - workshop.active_facilitators.each do | facilitator | - - facilitators << facilitator.name - = facilitators.join ', ' - = data_set(:h5, 'articles.workshops.headings.needs') do - - needs = [] - - JSON.parse(workshop.needs || '[]').each do | need | - - needs << (_"workshop.options.needs.#{need}") - = _!(needs.join ', ') - = data_set(:h5, 'articles.workshops.headings.theme') do - = workshop.theme.present? ? (_"workshop.options.theme.#{workshop.theme}") : '' - = data_set(:h5, 'articles.workshops.headings.space') do - = workshop.space.present? ? (_"workshop.options.space.#{workshop.space}") : '' - = data_set(:h5, 'forms.labels.generic.info') do - = link_info_dlg truncate(workshop.info), (richtext workshop.info.html_safe), workshop.title - - if workshop.notes.present? && strip_tags(workshop.notes).length > 0 - = data_set(:h5, 'forms.labels.generic.notes') do - = link_info_dlg truncate(workshop.notes), (richtext workshop.notes.html_safe), workshop.title + - case time_data[:type] + - when :meal + - location = EventLocation.where(id: time_data[:item]['location'].to_i).first + - if location.present? + %a.event-detail-link=off_screen(time_data[:item]['title']) + %template.event-details + %h1.title=time_data[:item]['title'] + %p.address + = location.title + _!(': ') + = location_link location + .title= time_data[:item]['title'] + .location= location.title + - when :event + - if time_data[:item].event_location.present? + %a.event-detail-link=off_screen(time_data[:item][:title]) + %template.event-details + %h1.title=time_data[:item][:title] + %p.address + = time_data[:item].event_location.title + _!(': ') + = location_link time_data[:item].event_location + = richtext time_data[:item][:info], 1 + .title= time_data[:item][:title] + .location= time_data[:item].event_location.title + %td.status{rowspan: rowspan} + - if @entire_page + %ul.workshops-to-schedule + - @workshops.each do | workshop | + %li{id: "workshop-#{workshop.id}", class: workshop.block.present? ? 'booked' : 'not-booked'} + %h4.title= workshop.title + = form_tag administration_update_path(conference.slug, :schedule), class: 'js-xhr' do + .already-booked + .field-error='This block is already booked' + .workshop-description + .details + = data_set(:h5, 'articles.workshops.headings.interested_count') do + = workshop.interested_count + = data_set(:h5, 'articles.workshops.headings.facilitators') do + - facilitators = [] + - workshop.active_facilitators.each do | facilitator | + - facilitators << facilitator.name + = facilitators.join ', ' + = data_set(:h5, 'articles.workshops.headings.needs') do + - needs = [] + - JSON.parse(workshop.needs || '[]').each do | need | + - needs << (_"workshop.options.needs.#{need}") + = _!(needs.join ', ') + = data_set(:h5, 'articles.workshops.headings.theme') do + = workshop.theme.present? ? (_"workshop.options.theme.#{workshop.theme}") : '' + = data_set(:h5, 'articles.workshops.headings.space') do + = workshop.space.present? ? (_"workshop.options.space.#{workshop.space}") : '' + = data_set(:h5, 'forms.labels.generic.info') do + = link_info_dlg truncate(workshop.info), (richtext workshop.info.html_safe), workshop.title + - if workshop.notes.present? && strip_tags(workshop.notes).length > 0 + = data_set(:h5, 'forms.labels.generic.notes') do + = link_info_dlg truncate(workshop.notes), (richtext workshop.notes.html_safe), workshop.title - = hidden_field_tag :id, workshop.id - .drop-downs - = location_select workshop.event_location_id, small: true - = block_select workshop.block.present? ? "#{workshop.block['day']}:#{workshop.block['block']}" : nil, small: true - .actions.next-prev - = button_tag :deschedule, value: :deschedule_workshop, class: [:delete, 'booked-only', :small] - = button_tag :reschedule, value: :schedule_workshop, class: [:secondary, 'booked-only', :small] - = button_tag :schedule_workshop, value: :schedule_workshop, class: ['not-booked-only', :small] + = hidden_field_tag :id, workshop.id + .drop-downs + = location_select workshop.event_location_id, small: true + = block_select workshop.block.present? ? "#{workshop.block['day']}:#{workshop.block['block']}" : nil, small: true + .actions.next-prev + = button_tag :deschedule, value: :deschedule_workshop, class: [:delete, 'booked-only', :small] + = button_tag :reschedule, value: :schedule_workshop, class: [:secondary, 'booked-only', :small] + = button_tag :schedule_workshop, value: :schedule_workshop, class: ['not-booked-only', :small] diff --git a/app/views/conferences/stats.xlsx.haml b/app/views/conferences/stats.xlsx.haml index 50faf10..5353eb0 100644 --- a/app/views/conferences/stats.xlsx.haml +++ b/app/views/conferences/stats.xlsx.haml @@ -13,9 +13,9 @@ - format_xls 'table' do - workbook use_autowidth: true - format bg_color: '333333' - - format 'td', font_name: 'Calibri', bg_color: 'ffffff', fg_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, bg_color: 'ffffff', fg_color: '333333' - - format 'td.date.day', num_fmt: 14, font_name: 'Courier New', sz: 10, bg_color: 'ffffff', fg_color: '333333' - - format 'td.money', num_fmt: 2, font_name: 'Courier New', sz: 10, bg_color: 'ffffff', fg_color: '333333' - - format 'td.bold', font_name: 'Calibri', bg_color: 'ffffff', fg_color: '333333', b: true + - format 'td.date', 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/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index cea2507..d65a8d7 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -17,7 +17,7 @@ %ul.locales - @alt_lang_urls.each do |locale, url| %li - - locale_translation = language(locale, true) + - locale_translation = language_name(locale, true) %a{href: url, lang: locale} =_'translate.content.change_locale', "Read in #{locale_translation}", vars: {language: locale_translation}, locale: locale if locale != I18n.locale.to_s .site-info diff --git a/config/initializers/i18n.rb b/config/initializers/i18n.rb index a83777c..e69de29 100644 --- a/config/initializers/i18n.rb +++ b/config/initializers/i18n.rb @@ -1,263 +0,0 @@ -# require 'i18n/backend/active_record' -# require 'yaml' - -# if Rails.env.test? -# class DevTranslation < Translation -# self.table_name = 'translations' -# establish_connection :development -# end -# end - -# module I18n -# class MissingTranslationExceptionHandler < ExceptionHandler -# def self.lorem_ipsum(method, size) -# options = {:random => true} -# case method.to_s -# when 'c', 'char', 'character', 'characters' -# if size -# return (Forgery::LoremIpsum.characters size, options).capitalize -# end -# return Forgery::LoremIpsum.character, options -# when 'w', 'word', 'words' -# if size -# return (Forgery::LoremIpsum.words size, options).capitalize -# end -# #return'LOREM' -# return (Forgery::LoremIpsum.word options).capitalize -# when 's', 'sentence', 'sentences' -# if size -# return Forgery::LoremIpsum.sentences size, options -# end -# return (Forgery::LoremIpsum.sentence options).capitalize -# when 'p', 'paragraph', 'paragraphs' -# if size -# return Forgery::LoremIpsum.paragraphs size, options.merge({:sentences => 10}) -# end -# return Forgery::LoremIpsum.sentences 10, options -# when 't', 'title' -# return (Forgery::LoremIpsum.sentences 1, options).capitalize -# end -# return method -# end - -# def self.note(key, behavior = nil, behavior_size = nil) -# I18n.backend.needs_translation(key) -# if behavior -# if behavior.to_s == 'strict' -# return nil -# end -# return self.lorem_ipsum(behavior, behavior_size) -# end -# #key.to_s.gsub(/^world\..*\.(.+)\.name$/, '\1').gsub(/^.*\.(.+)?$/, '\1').gsub('_', ' ') -# key.to_s.gsub(/^world\.(.+)\.name$/, '\1').gsub(/^.*\.(.+)?$/, '\1').gsub('_', ' ') -# end - -# def call(exception, locale, key, options) -# if exception.is_a?(MissingTranslation) -# I18n::MissingTranslationExceptionHandler.note(key, options[:behavior] || nil, options[:behavior_size] || nil) -# else -# super -# end -# end -# end - -# module Backend -# class BikeBike < I18n::Backend::ActiveRecord -# @@needs_translation - -# @@translations_file = 'config/locales/translation-info.yml' -# @@translation_cache_file = 'config/locales/.translation-cache.yml' -# @@pluralization_rules_file = 'config/locales/pluralization-rules.yml' -# @@translation_cache -# @@testing_started = false -# @@hosts - -# def self.init_tests!(new_translations = nil) -# if Rails.env.test? -# if !@@testing_started -# @@testing_started = true -# File.open(@@translations_file, 'w+') -# File.open(@@translation_cache_file, 'w+') -# end -# if !new_translations.nil? -# record_translation(new_translations) -# end -# end -# end - -# def needs_translation(key) -# @@needs_translation ||= Array.new -# @@needs_translation << key -# end - -# def translate_control(translation) -# @@translationsOnThisPage = true -# datakeys = '' -# translation['vars'].each { |key, value| datakeys += ' data-var-' + key.to_s + '="' + value.to_s.gsub('"', '"') + '"' } -# ('' + (translation['html'] || translation['untranslated']) + '').to_s.html_safe -# end - -# def initialized? -# begin -# super -# rescue -# return false -# end -# end - -# def initialize -# if !File.exist?(@@translation_cache_file) -# File.open(@@translation_cache_file, 'w+') -# end -# @@translation_cache = YAML.load(File.read(@@translation_cache_file)) || Hash.new -# super -# end - -# def get_translation_info() -# begin -# YAML.load_file(@@translations_file) || {} -# rescue Exception => e -# # sometimes concurrency issues cause an exception during testing -# sleep(1/2.0) -# get_translation_info() -# end -# end - -# def get_pluralization_rules(locale) -# rules = YAML.load_file(@@pluralization_rules_file) -# rules[locale.to_sym] -# end - -# def get_language_codes() -# YAML.load_file(@@pluralization_rules_file).keys -# end - -# def set_locale(host) -# @@hosts ||= Hash.new -# default = I18n.default_locale.to_s -# lang = @@hosts[host] -# if lang === false -# lang = nil -# elsif lang.nil? -# if (lang = host.gsub(/^(dev|test|www)[\-\.](.*)$/, '\2').gsub(/^(([^\.]+)\.)?[^\.]+\.[^\.]+$/, '\2')).blank? || (host == "localhost") -# lang = default -# end -# if get_language_codes().include? lang -# if !language_enabled? lang -# I18n.locale = default -# return lang -# end -# else -# lang = nil -# end -# end -# I18n.locale = default unless lang.present? -# # return nil if the language doesn exist, false if it is not enabled, or the code if it is enabled -# lang.present? ? true : false -# end - -# def get_language_completion(lang) -# total = 0 -# complete = 0 -# get_translation_info().each { |k,v| -# total += 1 -# complete += v['languages'].include?(lang.to_s) ? 1 : 0 -# } -# (total ? complete / total.to_f : 0.0) * 100.0 -# end - -# def language_enabled?(lang) -# lang.to_s == I18n.default_locale.to_s || get_language_completion(lang) > 66 -# end - -# def request_translation(key, vars, options) -# locale = options[:locale].to_s -# options[:locale] = :en -# translation = I18n.translate(key, vars, options) -# result = JSON.load(open("http://translate.google.com/translate_a/t?client=t&text=#{URI::escape(translation)}&hl=en&sl=en&tl=#{locale}&ie=UTF-8&oe=UTF-8&multires=1&otf=1&ssel=3&tsel=3&sc=1").read().gsub(/,+/, ',').gsub(/\[,+/, '[').gsub(/,+\]/, ']')) -# while result.is_a?(Array) -# result = result[0] -# end -# return result -# end - -# def record_translation(key) -# translations = get_translation_info() -# translations ||= Hash.new - -# if key.is_a(Array) -# key.each { |k| translations[k.to_s] ||= Hash.new } -# else -# translations[key.to_s] ||= Hash.new -# end -# File.open(@@translations_file, 'w') { |f| f.write translations.to_yaml } -# end - -# protected -# def lookup(locale, key, scope = [], options = {}) -# result = nil - -# if key.is_a?(String) -# key = key.gsub(/(^\[|\])/, '').gsub(/\[/, '.') -# end - -# if @@translation_cache && @@translation_cache.has_key?(locale.to_s) && @@translation_cache[locale.to_s].has_key?(key.to_s) -# result = @@translation_cache[locale.to_s][key.to_s] -# end -# if !result -# result = super(locale, key, scope, options) - -# if Rails.env.test? && options[:behavior].to_s != 'scrict' -# if result -# @@translation_cache[locale.to_s] ||= Hash.new -# @@translation_cache[locale.to_s][key.to_s] = result -# File.open(@@translation_cache_file, 'w') { |f| f.write @@translation_cache.to_yaml } -# end - -# translations = get_translation_info() -# translations ||= Hash.new -# translations[key.to_s] ||= Hash.new -# translations[key.to_s]['languages'] ||= Array.new -# translations[key.to_s]['pages'] ||= Array.new -# if options['behavior'] -# translations[key.to_s]['behavior'] ||= options['behavior'] -# end -# vars = [] -# options.each { |o,v| -# if !I18n::RESERVED_KEYS.include?(o.to_sym) && o.to_s != 'behavior' && o.to_s != 'behavior_size' -# vars << o.to_sym -# end -# } -# if vars.size() > 0 -# translations[key.to_s]['vars'] = vars -# end -# unless translations[key.to_s].has_key?('data') -# translations[key.to_s]['data'] = Array.new -# DevTranslation.where("key = '#{key.to_s}' OR key LIKE '#{key.to_s}#{I18n::Backend::Flatten::FLATTEN_SEPARATOR}%'").each { |t| -# translations[key.to_s]['data'] << ActiveSupport::JSON.encode(t.becomes(Translation)) -# unless translations[key.to_s]['languages'].include?(t.locale.to_s) -# translations[key.to_s]['languages'] << t.locale.to_s -# end -# } -# end -# path = $page_info[:path] -# route = nil -# Rails.application.routes.routes.each { |r| -# if !route && r.path.match(path) -# route = r.path.spec.to_s.gsub(/\s*\(\.:\w+\)\s*$/, '') -# end -# } -# unless translations[key.to_s]['pages'].include?(route) -# translations[key.to_s]['pages'] << route -# end -# File.open(@@translations_file, 'w') { |f| f.write translations.to_yaml } -# end -# end - -# result -# end -# end -# end -# end - -# I18n.exception_handler = I18n::MissingTranslationExceptionHandler.new diff --git a/config/locales/en.yml b/config/locales/en.yml index bada916..056274b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -163,6 +163,10 @@ en: unknown: 'Please include your city or town, we could not find a locality from "%{value}"' name: empty: 'Please enter a valid name' + address: + empty: 'Please enter an address' + space: + empty: 'Please select a space' template: body: 'There were problems with the following fields:' header: @@ -861,6 +865,7 @@ en: articles: admin: stats: + description: On this page you can view a breakdown of the registration process so far as well as download more detailed data in spreadsheets. headings: bikes: Bikes donation_count: Number of donations @@ -872,25 +877,49 @@ en: registrations: Number of registrations completed_registrations: Number of registrations incomplete_registrations: Incomplete registrations + meals: + description: On this page you can schedule the meals that you will be serving. + no_locations_warning: Before you can add meals, you must first add locations. + events: + description: On this page you can schedule events. Events are any type of event that isn't a meal or a workshop. You can scheulde group meetings, parties, or group ride for example. + no_locations_warning: Before you can add events, you must first add locations. + schedule: + 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. headings: guests: Guests email: Email housing: Preference 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: add_event: Add Event add_location: Add Location + add_meal: Add a Meal amenities: Amenities edit_event: Edit Event edit_location: Edit Location + paragraphs: + title: Give your location a title, for example "The Bike Kitchen" or "Smith Park" + meal_title: Give your meal a title, for example "Breakfast" + meal_info: Describe your meal. This will only be visible to conference hosts. + address: Enter the street address (without the city) of the location + space: The space type will help you to schedule workshops. If workshops will occur in this space, select "Meeting Room", "Repair Space", or "Outdoor Space" as you feel this space best matches. Otherwise select event space. + amenities: Amenities match up to workshop needs. Selecting the amenities will help you match up a workshop with this location when a facilitator has requested a specific amenity. edit: + description: Edit basic info about your conference. Here you can open or close registration, edit what shows up on the front page, set up your payment details, and add members to your organization so that they can access these pages too. headings: host_organizations: Host Organizations members: Organization Members paypal_info: PayPal Info paragraphs: paypal_info: PayPal info is used for donations and fee payments. You must enter all fields to enable online fee payments, see the PayPal API credential guide for more information. + broadcast: + description: The broadcast tool is used to contact users through email. You can send messages en masse to select groups of users. + workshop_times: + description: Before you scheulde workshops, you must first create blocks of time when the workshops will be. contact: headings: contact: Send us a question or a complement @@ -1020,6 +1049,8 @@ en: test: Please take a look at this preview to ensure that you want to send this email. Clicking ‘Test’ will send the email only to you. Only after that then the email will be set to %{send_to_count} people. preview: Clicking ‘Send’ will send this message to %{send_to_count} people. Please confirm that you have verified that the test email sent to you is what you want to be sent. sent: Your message has been sent. + events: + info: Describe your event for anyone attending the conference. companion: Is there someone who you would like us to ensure that you are housed with? arrival_and_departure: If you don't need housing, just tell us how long you plan to hang out with Bike!Bike! host: