Browse Source

Editable registrations

development
Godwin 8 years ago
parent
commit
fe9dd2b493
  1. 89
      app/assets/javascripts/registrations.js
  2. 50
      app/assets/stylesheets/_application.scss
  3. 344
      app/controllers/conferences_controller.rb
  4. 53
      app/helpers/application_helper.rb
  5. 8
      app/models/conference_registration.rb
  6. 5
      app/models/user.rb
  7. 4
      app/views/conferences/_hosting.html.haml
  8. 2
      app/views/conferences/admin/_stats.html.haml
  9. 1
      config/locales/en.yml

89
app/assets/javascripts/registrations.js

@ -3,6 +3,7 @@
function filterTable() { function filterTable() {
forEach(document.getElementById('search-table').getElementsByTagName('TBODY')[0].getElementsByTagName('TR'), function(tr) { forEach(document.getElementById('search-table').getElementsByTagName('TBODY')[0].getElementsByTagName('TR'), function(tr) {
if (tr.classList.contains('editable')) {
tr.classList.remove('hidden'); tr.classList.remove('hidden');
var value = searchControl.value; var value = searchControl.value;
@ -15,6 +16,7 @@
} }
} }
} }
}
}); });
} }
@ -30,39 +32,50 @@
function saveRow(row) { function saveRow(row) {
if (row) { if (row) {
row.classList.remove('editing'); row.classList.remove('editing');
/*row.removeAttribute('data-editing'); var table = row.parentElement.parentElement;
forEach(row.getElementsByTagName('TD'), function(cell) { var editRow = row.nextSibling;
var input = cell.getElementsByClassName('cell-editor')[0]; var url = table.getAttribute('data-update-url');
if (input) { var data = new FormData();
cell.removeChild(input); var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4) {
row.classList.remove('requesting');
if (request.status == 200 && request.responseText) {
var tempTable = document.createElement('table');
tempTable.innerHTML = request.responseText;
var rows = tempTable.getElementsByTagName('tr');
row.innerHTML = rows[0].innerHTML;
editRow.innerHTML = rows[1].innerHTML;
}
}
}
request.open('POST', url, true);
cells = editRow.getElementsByClassName('cell-editor');
data.append('key', row.getAttribute('data-key'));
var changed = false;
for (var i = 0; i < cells.length; i++) {
if (cells[i].value !== cells[i].getAttribute('data-value')) {
data.append(cells[i].getAttribute('name'), cells[i].value);
changed = true;
}
}
if (changed) {
row.classList.add('requesting');
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.send(data);
} }
});*/
} }
} }
function editTableCell(cell) { function editTableCell(cell) {
if (selectorMatches(cell, 'tr[data-key].editable td')) { if (selectorMatches(cell, 'tr[data-key].editable td')) {
editTableRow(cell.parentElement, cell); editTableRow(cell.parentElement, cell);
} } else if (!selectorMatches(cell, 'tr[data-key].editable + tr, tr[data-key].editable + tr *')) {
/*var currentRow = document.querySelector('[data-key][data-editing="1"]'); var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow && !currentRow.contains(cell)) { if (currentRow) {
saveRow(currentRow); saveRow(currentRow);
} }
if (selectorMatches(cell, 'tr[data-key] td[name]')) {
if (!cell.getElementsByClassName('cell-editor').length) {
//var tr = cell.parentElement;
//saveRow(document.querySelector('[data-key][data-editing="1"]'), tr);
cell.parentElement.setAttribute('data-editing', "1");
var value = cell.innerHTML;
cell.innerHTML += '<textarea type="text" name="' + cell.getAttribute('name') + '" class="cell-editor">' + value + '</textarea>';
cell.parentElement.classList.add();
setTimeout(function() { cell.getElementsByClassName('cell-editor')[0].focus(); }, 100);
} }
}*/
} }
function editTableRow(row, cell) { function editTableRow(row, cell) {
if (selectorMatches(row, 'tr[data-key].editable')) { if (selectorMatches(row, 'tr[data-key].editable')) {
@ -78,11 +91,39 @@
if (cell) { if (cell) {
focusElement = editor.querySelector('td[data-column-id="' + cell.getAttribute('data-column-id') + '"] .cell-editor'); focusElement = editor.querySelector('td[data-column-id="' + cell.getAttribute('data-column-id') + '"] .cell-editor');
} }
(focusElement || editor.getElementsByClassName('cell-editor')[0]).focus(); focusElement = focusElement || editor.getElementsByClassName('cell-editor')[0];
focusElement.focus();
if (focusElement.tagName === 'TEXTAREA' || (focusElement.tagName === 'INPUT' && focusElement.type != 'number' && focusElement.type != 'email')) {
focusElement.setSelectionRange(0, focusElement.value.length);
}
} }
} }
} }
document.addEventListener('click', function (event) { editTableCell(event.target); }); document.addEventListener('click', function (event) { editTableCell(event.target); });
document.addEventListener('keyup', function (event) {
if (event.code === "Enter") {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
event.stopPropagation();
event.preventDefault();
var next = event.shiftKey ? 'previousSibling' : 'nextSibling';
var cell = document.activeElement.parentElement.getAttribute('data-column-id');
var row = currentRow[next] ? currentRow[next][next] : null;
if (!row) {
rows = currentRow.parentElement.children;
row = event.shiftKey ? rows[rows.length - 2] : rows[0];
}
editTableRow(row, row.querySelector('[data-column-id="' + cell + '"]'));
}
} else if (event.code === "Escape") {
var currentRow = document.querySelector('tr[data-key].editable.editing');
if (currentRow) {
event.stopPropagation();
event.preventDefault();
saveRow(currentRow);
}
}
});
if (document.observe) { if (document.observe) {
document.observe("focusin", function (event) { editTableCell(event.target); }); document.observe("focusin", function (event) { editTableCell(event.target); });
} else { } else {

50
app/assets/stylesheets/_application.scss

@ -185,7 +185,7 @@ table, .table {
} }
tr[data-key] { tr[data-key] {
cursor: default; cursor: cell;
&:hover { &:hover {
background-color: lighten($colour-2, 33%); background-color: lighten($colour-2, 33%);
@ -205,6 +205,16 @@ table, .table {
&.has-editor { &.has-editor {
opacity: 1; opacity: 1;
@include after {
content: '';
position: absolute;
top: 100%;
right: 0;
left: 0;
height: 0.25em;
background-color: rgba($black, 0.125);
}
} }
.cell-editor { .cell-editor {
@ -224,8 +234,13 @@ table, .table {
overflow: hidden; overflow: hidden;
box-shadow: none; box-shadow: none;
text-align: inherit; text-align: inherit;
//border-bottom: 0.25em solid rgba(0,0,0,0.25);
&[type=number]::-webkit-inner-spin-button,
&[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
} }
}
select.cell-editor { select.cell-editor {
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
@ -233,6 +248,10 @@ table, .table {
appearance: none; appearance: none;
cursor: pointer; cursor: pointer;
} }
&.date .cell-editor {
text-align-last: right;
}
} }
} }
@ -269,15 +288,32 @@ table, .table {
td { td {
white-space: nowrap; white-space: nowrap;
&.text { &.date, &.datetime, &.money, &.number {
white-space: normal;
}
&.date, &.datetime, &.money {
font-family: monospace; font-family: monospace;
font-size: 1.25em; font-size: 1.25em;
text-align: right; text-align: right;
} }
&.text {
max-width: 20em;
}
}
}
tr.editable td.text,
tr.editor td.text .value {
overflow: hidden;
text-overflow: ellipsis;
}
tr.editor {
td.text .cell-editor {
white-space: normal;
bottom: auto;
height: 10em;
z-index: 1;
background: inherit;
overflow: auto !important;
} }
} }
} }

344
app/controllers/conferences_controller.rb

@ -336,94 +336,7 @@ class ConferencesController < ApplicationController
end end
end end
when :stats when :stats
@registrations = ConferenceRegistration.where(:conference_id => @this_conference.id).sort { |a,b| (a.user.present? ? (a.user.firstname || '') : '').downcase <=> (b.user.present? ? (b.user.firstname || '') : '').downcase } get_stats(!request.format.xlsx?)
@excel_data = {
columns: [
:name,
:email,
:status,
:registration_fees_paid,
:date,
:city,
:preferred_language,
:languages,
:arrival,
:departure,
:housing,
:bike,
:food,
:companion,
:companion_email,
:allergies
],
column_types: {
name: :bold,
date: :datetime,
arrival: [:date, :day],
departure: [:date, :day],
registration_fees_paid: :money,
allergies: :text
},
keys: {
name: 'forms.labels.generic.name',
email: 'forms.labels.generic.email',
status: 'forms.labels.generic.registration_status',
city: 'forms.labels.generic.location',
date: 'articles.conference_registration.terms.Date',
languages: 'articles.conference_registration.terms.Languages',
preferred_language: 'articles.conference_registration.terms.Preferred_Languages',
arrival: 'forms.labels.generic.arrival',
departure: 'forms.labels.generic.departure',
housing: 'forms.labels.generic.housing',
bike: 'forms.labels.generic.bike',
food: 'forms.labels.generic.food',
companion: 'articles.conference_registration.terms.companion',
companion_email: 'forms.labels.generic.email',
allergies: 'forms.labels.generic.allergies',
registration_fees_paid: 'articles.conference_registration.headings.fees_paid'
},
data: []
}
@registrations.each do | r |
user = r.user_id ? User.where(id: r.user_id).first : nil
if user.present?
companion = view_context.companion(r)
companion = companion.is_a?(User) ? companion.name : (view_context._"articles.conference_registration.terms.registration_status.#{companion}") if companion.present?
steps = r.steps_completed || []
@excel_data[:data] << {
id: r.id,
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") : '',
city: r.city || '',
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.present? ? (view_context._"articles.conference_registration.questions.housing.#{r.housing}") : '',
bike: r.bike.present? ? (view_context._"articles.conference_registration.questions.bike.#{r.bike}") : '',
food: r.food.present? ? (view_context._"articles.conference_registration.questions.food.#{r.food}") : '',
companion: companion,
companion_email: ((r.housing_data || {})['companions'] || ['']).first,
allergies: r.allergies,
registration_fees_paid: r.registration_fees_paid,
raw_values: {
housing: r.housing,
bike: r.bike,
food: r.food,
arrival: r.arrival,
departure: r.departure
},
html_values: {
date: r.created_at.present? ? r.created_at.strftime("%F %T") : '',
arrival: r.arrival.present? ? view_context.date(r.arrival.to_date, :span_same_year_date_1) : '',
departure: r.departure.present? ? view_context.date(r.departure.to_date, :span_same_year_date_1) : ''
}
}
end
end
if request.format.xlsx? if request.format.xlsx?
logger.info "Generating stats.xls" logger.info "Generating stats.xls"
@ -437,22 +350,6 @@ class ConferencesController < ApplicationController
@donation_count = 0 @donation_count = 0
@donations = 0 @donations = 0
@food = { meat: 0, vegan: 0, vegetarian: 0, all: 0 } @food = { meat: 0, vegan: 0, vegetarian: 0, all: 0 }
@column_options = {
housing: ConferenceRegistration.all_housing_options.map { |h| [
(view_context._"articles.conference_registration.questions.housing.#{h}"),
h] },
bike: ConferenceRegistration.all_bike_options.map { |b| [
(view_context._"articles.conference_registration.questions.bike.#{b}"),
b] },
food: ConferenceRegistration.all_food_options.map { |f| [
(view_context._"articles.conference_registration.questions.food.#{f}"),
f] },
arrival: view_context.conference_days_options_list(:before_plus_one),
departure: view_context.conference_days_options_list(:after_minus_one),
preferred_language: I18n.backend.enabled_locales.map { |l| [
(view_context.language_name l), l
] }
}
@registrations.each do | r | @registrations.each do | r |
if r.steps_completed.include? 'questions' if r.steps_completed.include? 'questions'
@completed_registrations += 1 @completed_registrations += 1
@ -576,6 +473,191 @@ class ConferencesController < ApplicationController
end end
def get_stats(html_format = false, id = nil)
@registrations = ConferenceRegistration.where(:conference_id => @this_conference.id).sort { |a,b| (a.user.present? ? (a.user.firstname || '') : '').downcase <=> (b.user.present? ? (b.user.firstname || '') : '').downcase }
@excel_data = {
columns: [
:name,
:email,
:status,
:is_attending,
:registration_fees_paid,
:date,
:city,
:preferred_language
] +
User.AVAILABLE_LANGUAGES.map { |l| "language_#{l}".to_sym } +
[
:arrival,
:departure,
:housing,
:bike,
:food,
:companion,
:companion_email,
:allergies,
:other,
:can_provide_housing,
:first_day,
:last_day,
:address,
:phone
] + ConferenceRegistration.all_spaces + [
:notes
],
column_types: {
name: :bold,
date: :datetime,
companion_email: :email,
arrival: [:date, :day],
departure: [:date, :day],
registration_fees_paid: :money,
allergies: :text,
other: :text,
first_day: [:date, :day],
last_day: [:date, :day],
notes: :text
},
keys: {
name: 'forms.labels.generic.name',
email: 'forms.labels.generic.email',
status: 'forms.labels.generic.registration_status',
is_attending: 'articles.conference_registration.terms.is_attending',
city: 'forms.labels.generic.location',
date: 'articles.conference_registration.terms.Date',
preferred_language: 'articles.conference_registration.terms.Preferred_Languages',
arrival: 'forms.labels.generic.arrival',
departure: 'forms.labels.generic.departure',
housing: 'forms.labels.generic.housing',
bike: 'forms.labels.generic.bike',
food: 'forms.labels.generic.food',
companion: 'articles.conference_registration.terms.companion',
companion_email: 'forms.labels.generic.email',
allergies: 'forms.labels.generic.allergies',
registration_fees_paid: 'articles.conference_registration.headings.fees_paid',
other: 'articles.conference_registration.headings.other',
can_provide_housing: 'articles.conference_registration.can_provide_housing',
first_day: 'forms.labels.generic.first_day',
last_day: 'forms.labels.generic.last_day',
notes: 'forms.labels.generic.notes',
phone: 'forms.labels.generic.phone',
address: 'forms.labels.generic.address'
},
data: []
}
User.AVAILABLE_LANGUAGES.each do | l |
@excel_data[:keys]["language_#{l}".to_sym] = "languages.#{l.to_s}"
end
ConferenceRegistration.all_spaces.each do |s|
@excel_data[:column_types][s] = :number
@excel_data[:keys][s] = "forms.labels.generic.#{s.to_s}"
end
@registrations.each do | r |
user = r.user_id ? User.where(id: r.user_id).first : nil
if user.present?
companion = view_context.companion(r)
companion = companion.is_a?(User) ? companion.name : (view_context._"articles.conference_registration.terms.registration_status.#{companion}") if companion.present?
steps = r.steps_completed || []
if id.nil? || id == r.id
housing_data = r.housing_data || {}
availability = housing_data['availability'] || []
availability[0] = Date.parse(availability[0]) if availability[0].present?
availability[1] = Date.parse(availability[1]) if availability[1].present?
data = {
id: r.id,
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')}"),
is_attending: (view_context._"articles.conference_registration.questions.bike.#{r.is_attending == 'n' ? 'no' : 'yes'}"),
date: r.created_at ? r.created_at.strftime("%F %T") : '',
city: r.city || '',
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.present? ? (view_context._"articles.conference_registration.questions.housing.#{r.housing}") : '',
bike: r.bike.present? ? (view_context._"articles.conference_registration.questions.bike.#{r.bike}") : '',
food: r.food.present? ? (view_context._"articles.conference_registration.questions.food.#{r.food}") : '',
companion: companion,
companion_email: (housing_data['companions'] || ['']).first,
allergies: r.allergies,
registration_fees_paid: r.registration_fees_paid,
other: r.other,
can_provide_housing: r.can_provide_housing ? (view_context._'articles.conference_registration.questions.bike.yes') : '',
first_day: availability[0].present? ? availability[0].strftime("%F %T") : '',
last_day: availability[1].present? ? availability[1].strftime("%F %T") : '',
notes: housing_data['notes'],
address: housing_data['address'],
phone: housing_data['phone'],
raw_values: {
housing: r.housing,
bike: r.bike,
food: r.food,
arrival: r.arrival.present? ? r.arrival.to_date : nil,
departure: r.departure.present? ? r.departure.to_date : nil,
preferred_language: user.locale,
is_attending: r.is_attending != 'n',
can_provide_housing: r.can_provide_housing,
first_day: availability[0].present? ? availability[0].to_date : nil,
last_day: availability[1].present? ? availability[1].to_date : nil
},
html_values: {
date: r.created_at.present? ? r.created_at.strftime("%F %T") : '',
arrival: r.arrival.present? ? view_context.date(r.arrival.to_date, :span_same_year_date_1) : '',
departure: r.departure.present? ? view_context.date(r.departure.to_date, :span_same_year_date_1) : '',
first_day: availability[0].present? ? view_context.date(availability[0].to_date, :span_same_year_date_1) : '',
last_day: availability[1].present? ? view_context.date(availability[1].to_date, :span_same_year_date_1) : ''
}
}
User.AVAILABLE_LANGUAGES.each do | l |
can_speak = ((user.languages || []).include? l.to_s)
data["language_#{l}".to_sym] = (can_speak ? (view_context._'articles.conference_registration.questions.bike.yes') : '')
data[:raw_values]["language_#{l}".to_sym] = can_speak
end
ConferenceRegistration.all_spaces.each do |s|
space = (housing_data['space'] || {})[s.to_s]
data[s] = space.present? ? space.to_i : nil
end
@excel_data[:data] << data
end
end
end
if html_format
yes_no = [
[(view_context._"articles.conference_registration.questions.bike.yes"), true],
[(view_context._"articles.conference_registration.questions.bike.no"), false]
]
@column_options = {
housing: ConferenceRegistration.all_housing_options.map { |h| [
(view_context._"articles.conference_registration.questions.housing.#{h}"),
h] },
bike: ConferenceRegistration.all_bike_options.map { |b| [
(view_context._"articles.conference_registration.questions.bike.#{b}"),
b] },
food: ConferenceRegistration.all_food_options.map { |f| [
(view_context._"articles.conference_registration.questions.food.#{f}"),
f] },
arrival: view_context.conference_days_options_list(:before_plus_one),
departure: view_context.conference_days_options_list(:after_minus_one),
preferred_language: I18n.backend.enabled_locales.map { |l| [
(view_context.language_name l), l
] },
is_attending: yes_no,
can_provide_housing: yes_no,
first_day: view_context.conference_days_options_list(:before),
last_day: view_context.conference_days_options_list(:after)
}
User.AVAILABLE_LANGUAGES.each do | l |
@column_options["language_#{l}".to_sym] = [
[(view_context._"articles.conference_registration.questions.bike.yes"), true]
]
end
end
end
def get_housing_data def get_housing_data
@hosts = {} @hosts = {}
@guests = {} @guests = {}
@ -699,6 +781,60 @@ class ConferencesController < ApplicationController
@admin_step = params[:admin_step] @admin_step = params[:admin_step]
case params[:admin_step] case params[:admin_step]
when 'stats'
registration = ConferenceRegistration.where(
id: params[:key].to_i,
conference_id: @this_conference.id
).limit(1).first
user_changed = false
params.each do | key, value |
case key.to_sym
when :city
registration.city = value.present? ? view_context.location(Geocoder.search(value, language: @this_conference.locale).first, @this_conference.locale) : nil
when :housing, :bike, :food, :allergies, :other
registration.send("#{key.to_s}=", value)
when :registration_fees_paid
registration.registration_fees_paid = value.to_i
when :can_provide_housing
registration.send("#{key.to_s}=", value.present?)
when :arrival, :departure
registration.send("#{key.to_s}=", value.present? ? Date.parse(value) : nil)
when :companion_email
registration.housing_data ||= {}
registration.housing_data['companions'] = [value]
when :preferred_language
registration.user.locale = value
user_changed = true
when :is_attending
registration.is_attending = value.present? ? 'y' : 'n'
when :address, :phone, :first_day, :last_day, :notes
registration.housing_data ||= {}
registration.housing_data[key.to_s] = value
else
if key.start_with?('language_')
l = key.split('_').last
if User.AVAILABLE_LANGUAGES.include? l.to_sym
registration.user.languages ||= []
if value.present?
registration.user.languages |= [l]
else
registration.user.languages -= [l]
end
user_changed = true
end
elsif ConferenceRegistration.all_spaces.include? key.to_sym
registration.housing_data ||= {}
registration.housing_data['space'] ||= {}
registration.housing_data['space'][key.to_s] = value
end
end
end
registration.user.save! if user_changed
registration.save!
get_stats(true, params[:key].to_i)
options = view_context.registrations_table_options
options[:html] = true
return render html: view_context.excel_rows(@excel_data, {}, options)
when 'edit' when 'edit'
case params[:button] case params[:button]
when 'save' when 'save'

53
app/helpers/application_helper.rb

@ -756,7 +756,7 @@ module ApplicationHelper
belongs_to_periods << :before_plus_one if day <= (conference.start_date + 1.day) belongs_to_periods << :before_plus_one if day <= (conference.start_date + 1.day)
belongs_to_periods << :after_minus_one if day >= (conference.end_date - 1.day) belongs_to_periods << :after_minus_one if day >= (conference.end_date - 1.day)
belongs_to_periods << :during if day >= conference.start_date && day <= conference.end_date belongs_to_periods << :during if day >= conference.start_date && day <= conference.end_date
days << [date(day.to_date, format || :span_same_year_date_1), day] if belongs_to_periods.include?(period) days << [date(day.to_date, format || :span_same_year_date_1), day.to_date] if belongs_to_periods.include?(period)
end end
return days return days
end end
@ -1558,6 +1558,7 @@ module ApplicationHelper
format 'td.datetime', 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.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.money', num_fmt: 2, font_name: 'Courier New', sz: 10, fg_color: '333333'
format 'td.number', font_name: 'Courier New', sz: 10, fg_color: '333333'
format 'td.bold', font_name: 'Calibri', fg_color: '333333', b: true format 'td.bold', font_name: 'Calibri', fg_color: '333333', b: true
end end
@ -1670,16 +1671,27 @@ module ApplicationHelper
if (options[:column_names] || []).include? column if (options[:column_names] || []).include? column
attributes[:class] << 'has-editor' attributes[:class] << 'has-editor'
raw_value = value raw_value = row[:raw_values][column] || value
if options[:html] && row[:html_values].present? && row[:html_values][column].present? if options[:html] && row[:html_values].present? && row[:html_values][column].present?
value = row[:html_values][column] value = row[:html_values][column]
end end
editor_attributes = { class: 'cell-editor', data: { value: raw_value.to_s } }
# create the control but add the original value to set the width and height # create the control but add the original value to set the width and height
editor_value = content_tag(:span, CGI::escapeHTML(value), class: 'value')
if (options[:column_options] || {})[column].present? if (options[:column_options] || {})[column].present?
value = (value + select_tag(column, options_for_select(options[:column_options][column], row[:raw_values][column] || raw_value), class: 'cell-editor')).html_safe value = (editor_value.html_safe + select_tag(column, options_for_select([['', '']] + options[:column_options][column], raw_value), editor_attributes)).html_safe
elsif data[:column_types][column] == :text
editor_attributes[:name] = column
value = (editor_value.html_safe + content_tag(:textarea, raw_value, editor_attributes)).html_safe
else else
value = (value + content_tag(:textarea, raw_value, name: column, class: 'cell-editor')).html_safe editor_attributes[:name] = column
editor_attributes[:value] = raw_value
type = data[:column_types][column] || :unknown
editor_attributes[:type] = { money: :number, number: :number, email: :email }[type] || :text
value = (editor_value.html_safe + content_tag(:input, nil, editor_attributes)).html_safe
end end
end end
@ -1724,7 +1736,6 @@ module ApplicationHelper
if options[:editable] if options[:editable]
attributes[:class] << :editable attributes[:class] << :editable
# attributes[:tabindex] = 0
end end
rows += content_tag(:tr, excel_columns(row, data, padding, options), attributes) + rows += content_tag(:tr, excel_columns(row, data, padding, options), attributes) +
@ -1734,6 +1745,38 @@ module ApplicationHelper
rows.html_safe rows.html_safe
end end
def registrations_table_options
{
id: 'search-table',
class: ['registrations', 'admin-edit'],
primary_key: :id,
column_names: [
:registration_fees_paid,
:is_attending,
:city,
:preferred_language,
:arrival,
:departure,
:housing,
:bike,
:food,
:companion_email,
:allergies,
:other,
:can_provide_housing,
:address,
:phone,
:first_day,
:last_day,
:notes
] +
User.AVAILABLE_LANGUAGES.map { |l| "language_#{l}".to_sym } +
ConferenceRegistration.all_spaces,
editable: administration_update_path(@this_conference.slug, :stats),
column_options: @column_options
}
end
private private
def _original_content(value, lang) def _original_content(value, lang)
content_tag(:div, ( content_tag(:div, (

8
app/models/conference_registration.rb

@ -13,6 +13,10 @@ class ConferenceRegistration < ActiveRecord::Base
[:none, :tent, :house] [:none, :tent, :house]
end end
def self.all_spaces
[:bed_space, :floor_space, :tent_space]
end
def self.all_bike_options def self.all_bike_options
[:yes, :no] [:yes, :no]
end end
@ -20,4 +24,8 @@ class ConferenceRegistration < ActiveRecord::Base
def self.all_food_options def self.all_food_options
[:meat, :vegetarian, :vegan] [:meat, :vegetarian, :vegan]
end end
def self.all_considerations
[:vegan, :smoking, :pets, :quiet]
end
end end

5
app/models/user.rb

@ -13,7 +13,7 @@ class User < ActiveRecord::Base
accepts_nested_attributes_for :authentications accepts_nested_attributes_for :authentications
before_save do |user| before_save do |user|
user.locale = I18n.locale user.locale ||= I18n.locale
end end
def can_translate?(to_locale = nil, from_locale = nil) def can_translate?(to_locale = nil, from_locale = nil)
@ -48,9 +48,6 @@ class User < ActiveRecord::Base
user = where(email: email).first user = where(email: email).first
unless user unless user
# not really a good UX so we should fix this later
#do_404
#return
user = new(email: email) user = new(email: email)
user.save! user.save!
end end

4
app/views/conferences/_hosting.html.haml

@ -6,14 +6,14 @@
= textfield :address, @hosting_data['address'], required: true, heading: 'articles.conference_registration.headings.host.address', help: 'articles.conference_registration.paragraphs.host.address' = textfield :address, @hosting_data['address'], required: true, heading: 'articles.conference_registration.headings.host.address', help: 'articles.conference_registration.paragraphs.host.address'
= telephonefield :phone, @hosting_data['phone'], required: true = telephonefield :phone, @hosting_data['phone'], required: true
= fieldset :space, heading: 'articles.conference_registration.headings.host.space', help: 'articles.conference_registration.paragraphs.host.space' do = fieldset :space, heading: 'articles.conference_registration.headings.host.space', help: 'articles.conference_registration.paragraphs.host.space' do
- [:bed_space, :floor_space, :tent_space].each do | space | - ConferenceRegistration.all_spaces.each do | space |
= numberfield space, @hosting_data['space'][space.to_s] || 0, min: 0, required: true = numberfield space, @hosting_data['space'][space.to_s] || 0, min: 0, required: true
= fieldset :hosting_dates, heading: 'articles.conference_registration.headings.host.availability', help: 'articles.conference_registration.paragraphs.host.availability' do = fieldset :hosting_dates, heading: 'articles.conference_registration.headings.host.availability', help: 'articles.conference_registration.paragraphs.host.availability' do
- first_day_options = conference_days_options_list(:before) - first_day_options = conference_days_options_list(:before)
- last_day_options = conference_days_options_list(:after) - last_day_options = conference_days_options_list(:after)
= selectfield :first_day, @hosting_data['availability'][0] || first_day_options.first.last, first_day_options = selectfield :first_day, @hosting_data['availability'][0] || first_day_options.first.last, first_day_options
= selectfield :last_day, @hosting_data['availability'][1] || last_day_options.last.last, last_day_options = selectfield :last_day, @hosting_data['availability'][1] || last_day_options.last.last, last_day_options
= checkboxes :considerations, [:vegan, :smoking, :pets, :quiet], @hosting_data['considerations'], 'articles.conference_registration.host.considerations', heading: 'articles.conference_registration.headings.host.considerations', help: 'articles.conference_registration.paragraphs.host.considerations', vertical: true = checkboxes :considerations, ConferenceRegistration.all_considerations, @hosting_data['considerations'], 'articles.conference_registration.host.considerations', heading: 'articles.conference_registration.headings.host.considerations', help: 'articles.conference_registration.paragraphs.host.considerations', vertical: true
= textarea :notes, @hosting_data['notes'], help: 'articles.conference_registration.paragraphs.host.notes', edit_on: :focus = textarea :notes, @hosting_data['notes'], help: 'articles.conference_registration.paragraphs.host.notes', edit_on: :focus
.actions.next-prev .actions.next-prev
= button_tag (params[:step] == :save ? :save : :next), value: :hosting = button_tag (params[:step] == :save ? :save : :next), value: :hosting

2
app/views/conferences/admin/_stats.html.haml

@ -22,4 +22,4 @@
%h4 Registrations %h4 Registrations
= searchfield :search, nil, big: true = searchfield :search, nil, big: true
.table-scroller .table-scroller
= html_table @excel_data, id: 'search-table', class: ['registrations', 'admin-edit'], primary_key: :id, column_names: [:registration_fees_paid, :city, :preferred_language, :arrival, :departure, :housing, :bike, :food, :companion_email, :allergies], editable: administration_update_path(@this_conference.slug, :stats), column_options: @column_options = html_table @excel_data, registrations_table_options

1
config/locales/en.yml

@ -1117,6 +1117,7 @@ en:
registered: Registered registered: Registered
companion: Companion companion: Companion
Preferred_Languages: Preferred Language Preferred_Languages: Preferred Language
is_attending: Attending?
about_bikebike: about_bikebike:
paragraphs: paragraphs:
bicycle_project_paragraph: 'From collectives that use the bicycle as an excuse to change society, economy and the environment. Non-profit groups that have a community bike shops, cooperatives and other projects that promote the use of the bicycle and that come together to turn their communities into a place where riding is easier, more inclusive, safer and more fun. The list below uses the criteria found in the old Bicycle Organization Organization Project for what constitutes a community bike shop. The bike project need not meet all these criteria. Rather, it is a general list of qualities which are common among many bicycle projects.' bicycle_project_paragraph: 'From collectives that use the bicycle as an excuse to change society, economy and the environment. Non-profit groups that have a community bike shops, cooperatives and other projects that promote the use of the bicycle and that come together to turn their communities into a place where riding is easier, more inclusive, safer and more fun. The list below uses the criteria found in the old Bicycle Organization Organization Project for what constitutes a community bike shop. The bike project need not meet all these criteria. Rather, it is a general list of qualities which are common among many bicycle projects.'

Loading…
Cancel
Save