Fixed FR policy translation

This commit is contained in:
Godwin
2017-05-30 19:17:02 -07:00
parent 26adfdcbd5
commit 4115c8996f
15 changed files with 467 additions and 935 deletions
+16
View File
@@ -171,10 +171,20 @@
}, node || document);
forEachElement('form.js-xhr', function(form) {
if (form.addEventListener) {
forEachElement('button', function(button) {
button.addEventListener('click', function(event) {
form.setAttribute('data-button-name', button.name);
form.setAttribute('data-button-value', button.value);
});
}, form);
form.addEventListener('submit', function(event) {
event.preventDefault();
form.classList.add('requesting');
var data = new FormData(form);
var button = form.getAttribute('data-button-value');
if (button) {
data.append(form.getAttribute('data-button-name'), button);
}
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4) {
@@ -197,6 +207,12 @@
if (response[i].className) {
element.className = response[i].className;
}
if (response[i].scrollTo) {
var scrollTo = document.querySelector(response[i].scrollTo);
if (scrollTo) {
scrollTo.scrollIntoView();
}
}
}
}
}
+219 -16
View File
@@ -58,6 +58,14 @@ legend {
p {
font-size: 4vw;
&.center {
text-align: center;
}
}
u {
@include _(text-decoration-color, rgba($black, 0.5));
}
a {
@@ -140,7 +148,7 @@ table, .table {
}
th, .table-th {
background-color: #F8F8F8;
background-color: $extra-light-gray;
&.corner {
background-color: transparent;
@@ -345,7 +353,7 @@ table, .table {
.table-scroller {
overflow: auto;
background-color: #F8F8F8;
background-color: $extra-light-gray;
@include _(box-shadow, inset 0 0 10em 0 rgba(0,0,0,0.125));
table {
@@ -425,8 +433,8 @@ body.expanded-element {
background-color: $white;
td.empty {
background-color: #F8F8F8;
border-bottom-color: #F8F8F8;
background-color: $extra-light-gray;
border-bottom-color: $extra-light-gray;
}
}
@@ -449,7 +457,7 @@ body.expanded-element {
margin: auto;
overflow: auto;
z-index: 1002;
background-color: #F8F8F8;
background-color: $extra-light-gray;
flex: 1;
}
@@ -516,6 +524,138 @@ button,
&.small {
font-size: 0.9em;
}
&.unstyled {
height: 4em;
margin: 0;
padding: 0;
border: 0;
border-radius: 0;
font-family: inherit;
color: $black;
@include _(box-shadow, none);
@include _(text-stroke, 0);
}
}
table.calendar {
width: 100%;
table-layout: fixed;
margin: 0;
button {
width: 100%;
background-color: $white;
&.during-conference {
background-color: rgba($colour-1, 0.25);
}
&.selected {
border: 0.25em solid rgba($colour-2, 0.5);
}
}
td {
padding: 0;
background-color: $extra-light-gray;
}
tr.month th {
background-color: rgba($colour-5, 0.25);
font-size: 1.5em;
}
}
#main .actions {
&.center {
text-align: center;
}
.buttons {
display: inline-block;
button {
margin: 0 0.333em;
}
}
button[value="back"] {
float: left;
background-color: $mid-gray;
}
}
#main {
.registration-step-options,
.vertical-registration-step-options {
text-align: center;
button {
display: block;
padding: 0 2em;
border: 0.05em solid $black;
background-color: $white;
&.selected {
// background-color: rgba($colour-1, 0.25);
box-shadow: 0 0 0 0.25em rgba($colour-2, 0.5);
}
}
}
.registration-step-options {
display: table;
table-layout: fixed;
margin: 0 auto;
.options {
display: table-row;
}
button {
display: table-cell;
margin: 0 0.5em;
height: 3em;
}
}
.vertical-registration-step-options {
text-align: center;
.options {
display: inline-block;
}
button {
width: 100%;
margin: 0.5em auto;
}
}
}
#action-message {
display: none;
text-align: center;
margin-bottom: 1em;
&.error, &.complete {
display: block;
}
.message {
display: inline-block;
@include font-family(secondary);
font-size: 1.25em;
padding: 1em 2em;
border: 0.25rem solid $blue;
background-color: rgba($blue, 0.25);
}
&.error .message {
border-color: $red;
background-color: rgba($red, 0.25);
}
}
a.button {
@@ -661,6 +801,10 @@ input {
}
}
.multi-field {
margin-bottom: 4em;
}
.number-field,
.email-field,
.search-field,
@@ -712,7 +856,7 @@ input {
position: relative;
z-index: $zindex-base + 2;
padding: 0.15em 0.5em;
background-color: #F8F8F8;
background-color: $extra-light-gray;
@include _(border-radius, 0.25rem);
@include _(box-shadow, 0 0 0 0 rgba(0,0,0,0.05));
@include _(transition, box-shadow 200ms ease-in-out);
@@ -731,6 +875,11 @@ input {
&:focus, &:active, &:hover {
@include _(box-shadow, 0 0 0 0.3em rgba(0,0,0,0.05));
}
&[readonly] {
@include _(box-shadow, none);
@include _(opacity, 0.75);
}
}
}
@@ -758,7 +907,7 @@ input {
display: block;
text-align: right;
padding: 0.5em;
background-color: #F8F8F8;
background-color: $extra-light-gray;
@include _(border-radius, 0.25rem);
@include _(box-shadow, 0 0 0 0 rgba(0,0,0,0.05));
@include _(transition, box-shadow 200ms ease-in-out);
@@ -1579,7 +1728,7 @@ ul.warnings {
&.current {
border-color: #CCC;
background-color: #F8F8F8;
background-color: $extra-light-gray;
}
&:hover {
@@ -1813,7 +1962,7 @@ table.schedule {
td {
text-align: center;
border: 0;
background-color: #F8F8F8;
background-color: $extra-light-gray;
&.workshop {
@@ -2677,12 +2826,46 @@ html :focus {
}
}
.conferences-register .policy-agreement {
padding: 0.25em 1em;
margin: 0 0 3em;
border: 0.1em solid #DDD;
@include _(border-radius, 0.25em);
@include default-box-shadow(top, 2);
.conferences-register #main article .policy-agreement {
ul {
padding: 0;
list-style: none;
}
.term {
display: block;
font-style: italic;
overflow: auto;
padding: 0.5em;
border-bottom: 0.1em solid rgba(51, 51, 51, 0.125);
font-family: inherit;
}
li {
margin-bottom: 0;
&:last-child .term {
border: 0;
}
}
input {
width: 1.1em;
height: 1.1em;
margin-top: 0.75em;
margin-left: 0.5em;
float: right;
cursor: pointer;
&:hover + .term {
background-color: rgba($colour-3, 0.25);
}
&:checked + .term {
font-style: normal;
background-color: rgba($colour-5, 0.125);
}
}
}
body.policy .policy-agreement ul {
@@ -2898,7 +3081,7 @@ body.policy .policy-agreement ul {
border: 0.1em solid #DDD;
padding: 1em;
margin: 1em 0 3em 0;
background-color: #F8F8F8;
background-color: $extra-light-gray;
@include _(border-radius, 0.25em);
}
@@ -3112,6 +3295,20 @@ body.policy .policy-agreement ul {
}
}
.multi-field {
display: table;
width: 100%;
.input-field {
display: table-cell;
padding-right: 1em;
&:last-child {
padding-right: 0;
}
}
}
.flex-column {
@include _-(display, flex);
@include _(align-items, flex-start);
@@ -3300,6 +3497,12 @@ body.policy .policy-agreement ul {
}
}
.conferences-register #main article .policy-agreement .term {
// make it a little more difficult for desktop users
// to help ensure they read each point
pointer-events: none;
}
#header-title {
min-height: rems(35);
font-size: 1em;
+1
View File
@@ -11,6 +11,7 @@ $colour-5: #02CA9E; // green
$white: #FFFEFE;
$black: #333;
$gray: #E8E8E8;
$extra-light-gray: #F8F8F8;
$light-gray: #EEE;
$mid-gray: #888;
$red: #FF5A5F;
+16 -1
View File
@@ -3,7 +3,7 @@ class ApplicationController < BaseController
before_filter :capture_page_info
helper_method :protect
helper_method :protect, :policies
# @@test_host
# @@test_location
@@ -646,4 +646,19 @@ class ApplicationController < BaseController
UserMailer.send(*args).deliver_now
end
end
def policies
[
:commitment,
:respect,
:empowerment,
:accessible,
:peaceful,
:spaces,
:hearing,
:intent,
:open_minds,
:learning
]
end
end
+48 -1
View File
@@ -1,7 +1,9 @@
require 'geocoder/calculations'
require 'rest_client'
require 'registration_controller_helper'
class ConferencesController < ApplicationController
include RegistrationControllerHelper
def list
@page_title = 'articles.conferences.headings.Conference_List'
@@ -40,6 +42,51 @@ class ConferencesController < ApplicationController
def register
set_conference
do_403 unless @this_conference.is_public || @this_conference.host?(current_user)
do_403 unless @this_conference.registration_open
if logged_in?
if request.post?
# update this step
result = update_registration_step(params[:step].to_sym, @this_conference, current_user, params)
# set the message if we got one
@update_status = result[:status]
@update_message = result[:message]
# pass any data on to the view
(result[:data] || {}).each do |key, value|
instance_variable_set("@#{key}", value) unless instance_variable_defined?("@#{key}")
end
if result[:exception].present? && Rails.env.development?
raise result[:exception]
end
end
# get the current step
@step = current_registration_step(@this_conference, current_user)
# set up the next step
result = registration_step(@step, @this_conference, current_user)
# pass any data on to the view
(result || {}).each do |key, value|
instance_variable_set("@#{key}", value) unless instance_variable_defined?("@#{key}")
end
end
if request.xhr?
render json: [{
globalSelector: '#step-content',
html: render_to_string(partial: "registration_steps/#{@step}"),
scrollTo: '#action-message .message, #step-content'
}]
end
end
def old_register
set_conference
@register_template = nil
@@ -124,7 +171,7 @@ class ConferencesController < ApplicationController
@page_title = 'articles.conference_registration.headings.Payment'
else
case form_step
case form_step
when :confirm_email
return confirm_email(params[:email], params[:token], register_path(@this_conference.slug))
when :contact_info
+71 -22
View File
@@ -11,7 +11,7 @@ module FormHelper
# set the selected locale
selected_locale = (options[:locale] || object.locale || I18n.locale).to_sym
I18n.backend.enabled_locales.each do | locale |
I18n.backend.enabled_locales.each do |locale|
# ses if this should b the selected field
class_name = selected_locale == locale.to_sym ? 'selected' : nil
@@ -21,7 +21,7 @@ module FormHelper
class: class_name, data: { locale: locale }).html_safe
fields = ''
field_options.each do | name, __options |
field_options.each do |name, __options|
_options = __options.deep_dup
# add the field
value = object.is_a?(Hash) ? object[locale.to_sym] : object.get_column_for_locale!(name, locale, false)
@@ -69,7 +69,7 @@ module FormHelper
# set the selected locale
selected_locale = (options[:locale] || object.locale || I18n.locale).to_sym
I18n.backend.enabled_locales.each do | locale |
I18n.backend.enabled_locales.each do |locale|
# ses if this should b the selected field
class_name = selected_locale == locale.to_sym ? 'selected' : nil
@@ -227,7 +227,7 @@ module FormHelper
unless select_options.first.is_a?(Array)
so = select_options
select_options = []
so.each do | opt |
so.each do |opt|
select_options << [ I18n.t("forms.options.#{name.to_s}.#{opt.to_s}"), opt]
end
end
@@ -315,7 +315,8 @@ module FormHelper
input_options = {
id: id,
required: options[:required],
required: Rails.env.test? || Rails.env.development? ? false : options[:required],
readonly: options[:readonly] == true ? :readonly : nil,
lang: options[:lang],
min: options[:min],
max: options[:max],
@@ -431,7 +432,7 @@ module FormHelper
is_single = !values.is_a?(Array)
if boxes.length > 0
if boxes.first.is_a?(Array)
labels = boxes.map(&:first)
labels = boxes.map(&:first) unless label_key == false
boxes = boxes.map(&:last)
end
elsif !boxes.first.is_a?(Integer)
@@ -458,17 +459,21 @@ module FormHelper
# we only need the required attribute on one element
required = false
if labels.present?
label = labels[i]
elsif is_single
label = _(label_key.to_s)
elsif box.is_a?(Integer)
label = I18n.t(label_key.to_s)[box]
if label_key == false
boxes_html += label_tag(id, '')
else
label = _("#{label_key.to_s}.#{box}")
if labels.present?
label = labels[i]
elsif is_single
label = _(label_key.to_s)
elsif box.is_a?(Integer)
label = I18n.t(label_key.to_s)[box]
else
label = _("#{label_key.to_s}.#{box}")
end
boxes_html += label_tag(id, label)
end
boxes_html += label_tag(id, label)
end
if options[:other].present? && !is_single
@@ -519,6 +524,50 @@ module FormHelper
button_tag(value, options, &block)
end
def calendar_day_select(name, value, date_range, highlight_range = nil)
months = {}
date_range.to_a.each do |d|
unless months[d.month].present?
months[d.month] = [nil] * d.wday
end
months[d.month] << d
end
rows = []
empty_cell = content_tag(:td, '').html_safe
month_names = I18n.t('date.month_names')
day_names = content_tag(:tr, I18n.t('date.abbr_day_names').map { |day| content_tag(:th, day).html_safe }.join.html_safe).html_safe
months.each do |month, days|
rows << content_tag(:tr, content_tag(:th, month_names[month], colspan: 7).html_safe, class: 'month').html_safe
rows << day_names
weekdays = []
days.each do |date|
if date.nil?
weekdays << empty_cell
else
class_name = ['unstyled']
if value == date
class_name << 'selected'
end
if highlight_range.present? && highlight_range.include?(date)
class_name << 'during-conference'
end
weekdays << content_tag(:td,
content_tag(:button, date.day.to_s, name: :date, value: date.to_s, class: class_name).html_safe
).html_safe
end
if date.present? && date.wday >= 6
rows << content_tag(:tr, weekdays.join.html_safe).html_safe if weekdays.present?
weekdays = []
end
end
weekdays += [empty_cell] * (7 - weekdays.length)
rows << content_tag(:tr, weekdays.join.html_safe).html_safe if weekdays.present?
end
return content_tag(:table, rows.join.html_safe, class: :calendar).html_safe
end
def conference_days_options(conference = nil)
conference ||= @this_conference || @conference
return [] unless conference
@@ -558,7 +607,7 @@ module FormHelper
return [] unless conference
options = Array.new
[:closed, :pre, :open].each do | opt |
[:closed, :pre, :open].each do |opt|
options << [(_"forms.labels.generic.registration_statuses.#{opt}"), opt]
end
@@ -601,7 +650,7 @@ module FormHelper
def contact_reason_select
reasons = []
[:website, :conference].each do | reason |
[:website, :conference].each do |reason|
reasons << [ _("forms.labels.generic.reasons.#{reason.to_s}"), reason ]
end
[['Something about the website', :website]]
@@ -610,8 +659,8 @@ module FormHelper
def block_select(value = nil, args = {})
blocks = {}
@workshop_blocks.each_with_index do | info, block |
info['days'].each do | day |
@workshop_blocks.each_with_index do |info, block|
info['days'].each do |day|
blocks[(day.to_i * 10) + block] = [ "#{(I18n.t 'date.day_names')[day.to_i]} Block #{block + 1}", "#{day}:#{block}" ]
end
end
@@ -621,7 +670,7 @@ module FormHelper
def location_select(value = nil, args = {})
locations = []
if @this_conference.event_locations.present?
@this_conference.event_locations.each do | location |
@this_conference.event_locations.each do |location|
locations << [ location.title, location.id ] unless ((args[:invalid_locations] || []).include? location.id)
end
end
@@ -640,7 +689,7 @@ module FormHelper
def host_options_list(hosts)
options = [[nil, nil]]
hosts.each do | id, registration |
hosts.each do |id, registration|
options << [registration.user.name, id]
end
return options
@@ -654,7 +703,7 @@ module FormHelper
post_registration_steps = ''
post_registration = false
steps.each do | step |
steps.each do |step|
text = _"articles.conference_registration.headings.#{step[:name].to_s}"
if step[:name] == :workshops
+65
View File
@@ -61,4 +61,69 @@ module RegistrationHelper
# if all else fails, return the first step
return steps.last[:name]
end
def registration_step_header(step = @step, vars = nil)
if step.is_a?(Hash)
vars = step
step = @step
end
vars ||= {}
row do
columns(medium: 12) do
registration_step_header_title(step, vars[:header])
end.html_safe +
columns(medium: 12) do
registration_step_header_description(step, vars[:description])
end.html_safe
end.html_safe
end
def registration_step_header_title(step = @step, vars = nil)
if step.is_a?(Hash)
vars = step
step = @step
end
content_tag(:h2, (_"articles.conference_registration.headings.#{@step}", :t, 2, vars: vars || {})).html_safe
end
def registration_step_header_description(step = @step, vars = nil)
if step.is_a?(Hash)
vars = step
step = @step
end
content_tag(:p, (_"articles.conference_registration.paragraphs.#{@step}", :p, 2, vars: vars || {})).html_safe
end
def save_registration_step(conference = @this_conference, step = @step, &block)
buttons = [:back]
case step.to_sym
when :policy
buttons = [:agree]
when :name, :languages, :org_location, :org_create_name, :org_create_address, :org_create_email, :org_create_mailing_address, :housing_companion_email, :housing_companion_invite, :housing_allergies, :housing_other
buttons = [:next, :back]
when :org_location_confirm
buttons = [:yes, :back]
when :review
buttons = nil
end
content = block.present? ? capture(&block) : ''
actions = ''
if buttons.present?
buttons.each do |button_name|
actions += (button button_name, value: button_name)
end
end
form_tag(register_path(conference.slug), class: 'js-xhr') do
(@update_message.present? && @update_status.present? ? columns(medium: 12, class: @update_status, id: 'action-message') do
content_tag(:div, (_"articles.conference_registration.#{@update_status}.#{@update_message}", :s), class: :message).html_safe
end : '').html_safe +
content.html_safe +
(hidden_field_tag :step, step).html_safe +
columns(medium: 12, class: [:actions, :center]) do
content_tag(:div, actions.html_safe, class: :buttons).html_safe
end.html_safe
end.html_safe
end
end
+15 -11
View File
@@ -1,12 +1,16 @@
.policy-agreement
- if @is_policy_page
%h2=_'articles.policy.headings.The_Agreement'
- else
%h3=_'articles.policy.headings.The_Agreement'
%ul
- [:commitment, :respect, :empowerment, :accessible, :peaceful, :spaces, :hearing, :intent, :open_minds, :learning].each do |term|
%li=_"articles.policy.term.#{term.to_s}", :s, 2
%h3=_'articles.policy.headings.Why','Why have a Safer Space Agreement?'
%p=_'articles.policy.paragraphs.Why', :p
%h3=_'articles.policy.headings.How','How is the policy enforced?'
%p=_'articles.policy.paragraphs.How', :p
- if @is_policy_page
%h2=_'articles.policy.headings.The_Agreement'
- else
%h3=_'articles.policy.headings.The_Agreement'
%ul
- policies.each do |term|
%li
- if checkboxes
= check_box_tag(term, 1, false, required: true)
.term=_"articles.policy.term.#{term.to_s}", :s, 2
- unless less_info
%h3=_'articles.policy.headings.Why','Why have a Safer Space Agreement?'
%p=_'articles.policy.paragraphs.Why', :p
%h3=_'articles.policy.headings.How','How is the policy enforced?'
%p=_'articles.policy.paragraphs.How', :p
@@ -1,7 +0,0 @@
.columns.medium-8
= f.check_box :registration_open, help: true
= f.text_area :preregistration_info, help: true
= f.text_area :registration_info, help: true
= f.text_area :postregistration_info, help: true
.columns
= f.actions :save
+7 -6
View File
@@ -1,12 +1,13 @@
= render :partial => 'conferences/page_header', :locals => {:page_key => 'Conference_Registration'}
- if @warnings.present?
= row class: 'warnings', tag: :ul do
- @warnings.each do | warning |
- @warnings.each do |warning|
= columns tag: :li, class: 'warning-info' do
= warning
%article
= row do
= columns(medium: 12) do
%h2=_(@page_title)
= registration_step_menu
= render "conferences/#{@register_template}"
- if logged_in?
#step-content= render "registration_steps/#{@step}"
- else
= row do
= columns(medium: 12) do
= render "application/login"
@@ -1,122 +0,0 @@
- location = @conference.organizations.first.locations.first
- location_name = location.city + ', ' + (location.territory ? Carmen::Country.coded(location.country).subregions.coded(location.territory).name : location.country)
- title @conference.title
- description "#{@conference.title} conference in #{location_name} for DIY bicycle collectives, co-ops, and advocacy groups"
= render 'header'
- stats = {confirmed: 0, completed: 0, total: 0, paid: 0, collected: 0, housing_total: 0, housing_beds: 0, housing_couches: 0, housing_campers: 0, bikes: 0, small_bikes: 0, large_bikes: 0}
%article.row
.columns.large-10
%h2=_'conference.registrations.title','Registrations'
%table.registrations
%tr
%th='Email'
%th='First Name'
%th='Last Name'
%th='Preferred Name'
%th='Confirmed?'
%th='Completed?'
%th='Paid?'
%th='Housing'
%th='Bike'
- @registrations.each do |registration|
%tr
- data = YAML.load(registration.data)
- user = User.find_user(registration.email)
- stats[:total] += 1
- stats[:confirmed] += (registration.is_confirmed ? 1 : 0)
- stats[:completed] += (registration.completed ? 1 : 0)
- stats[:paid] += (registration.registration_fees_paid ? 1 : 0)
- stats[:collected] += (registration.registration_fees_paid || 0)
- stats[:housing_total] += (data[:questions][:housing] == 'none' ? 0 : 1)
- stats[:housing_beds] += (data[:questions][:housing] == 'bed' ? 1 : 0)
- stats[:housing_couches] += (data[:questions][:housing] == 'couch' ? 1 : 0)
- stats[:housing_campers] += (data[:questions][:housing] == 'camp' ? 1 : 0)
- stats[:bikes] += (data[:questions][:housing] == 'no' ? 0 : 1)
- stats[:small_bikes] += (data[:questions][:housing] == 'small' ? 1 : 0)
- stats[:large_bikes] += (data[:questions][:housing] == 'large' ? 1 : 0)
- rows = 1 + (user.present? ? 1 : 0) + (data[:questions][:housing_extra].present? ? 1 :0) + (data[:questions][:other].present? ? 1 :0)
%td.user{rowspan: (rows > 1 ? rows : nil), id: user ? "user-#{user.id}" : nil}=registration.email
%td=data[:user][:firstname]
%td=data[:user][:lastname]
%td=data[:user][:username]
%td=registration.is_confirmed ? 'Yes' : 'No'
%td=registration.completed ? 'Yes' : 'No'
%td=registration.registration_fees_paid.nil? ? 'No' : 'Yes'
%td=data[:questions][:housing]
%td=data[:questions][:loaner_bike]
- if user.present?
%tr
%th='Organizations'
%td{colspan: 3}
- UserOrganizationRelationship.where(:user_id => user.id).each do |rel|
- org = Organization.find(rel.organization_id)
- location_name = "#{org.locations[0].city}, #{org.locations[0].territory}"
= link_to "#{org.name} (#{location_name})", org
%th='Workshops'
%td{colspan: 3}
- Workshop.where('workshop_facilitators.user_id' => user.id, :conference_id => @conference.id).joins(:workshop_facilitators).each do | workshop |
%a{href: "#workshop-#{workshop.slug}"}= workshop.title
- if data[:questions][:housing_extra].present?
%tr
%th='Housing Notes'
%td{colspan: 7}=data[:questions][:housing_extra]
- if data[:questions][:other].present?
%tr
%th='Other Notes'
%td{colspan: 7}=data[:questions][:other]
%h3=_'conference.registrations.workshops.title','Workshops'
%ul
- Workshop.where(:conference_id => @conference.id).each do |workshop|
%li.workshop{id: "workshop-#{workshop.slug}"}
.columns
%h4=workshop.title
.columns.medium-10.medium-offset-1.end
= workshop.info.html_safe
.columns.medium-8.medium-offset-2.end
%h5='Facilitators'
- workshop.workshop_facilitators.each do |facilitator|
- user = User.find(facilitator.user_id)
%div
%a{href: "#user-#{user.id}"}="#{user.username} (#{user.email})"
- content_for :side_bar do
%h5='Stats'
%table
%tr
%th='Confirmed Registrations:'
%td=stats[:confirmed]
%tr
%th='Unconfirmed Registrations:'
%td=(stats[:total] - stats[:confirmed])
%tr
%th='Completed Registrations:'
%td=stats[:completed]
%tr
%th='Incomplete Registrations:'
%td=(stats[:total] - stats[:completed])
%tr
%th='Fees Collected:'
%td=number_to_currency(stats[:collected], :unit => '$')
%tr
%th='Housing Total:'
%td=stats[:housing_total]
%tr
%th='Beds:'
%td=stats[:housing_beds]
%tr
%th='Couch / Floorspace:'
%td=stats[:housing_couches]
%tr
%th='Campers:'
%td=stats[:housing_campers]
%tr
%th='Bikes Required:'
%td=stats[:bikes]
%tr
%th='Small Bikes:'
%td=stats[:small_bikes]
%tr
%th='Large Bikes:'
%td=stats[:large_bikes]
@@ -8,3 +8,4 @@
%a{href: workshop_link}=_!(workshop_link)
%p=_'email.workshop.paragraph.request_reply_instructions',"You can also reply directly to this email to ask follow-up questions."