Browse Source

Home page schedule, publish and unpublish schedule, extended user data in housing

development
Godwin 8 years ago
parent
commit
e9d9962d9a
  1. 52
      app/assets/javascripts/main.js
  2. 367
      app/assets/stylesheets/_application.scss
  3. 197
      app/controllers/application_controller.rb
  4. 710
      app/controllers/conferences_controller.rb
  5. 2
      app/models/organization.rb
  6. 4
      app/models/user.rb
  7. 14
      app/views/application/home.html.haml
  8. 2
      app/views/conferences/_questions.html.haml
  9. 23
      app/views/conferences/admin/_housing.html.haml
  10. 82
      app/views/conferences/admin/_schedule.html.haml
  11. 12
      app/views/conferences/admin/_stats.html.haml
  12. 6
      app/views/layouts/application.html.haml
  13. 2
      app/views/workshops/_workshop_previews.html.haml
  14. 2
      config/initializers/assets.rb
  15. 7
      config/locales/en.yml

52
app/assets/javascripts/main.js

@ -30,7 +30,38 @@
overlay.querySelector('.dlg.open').focus(); overlay.querySelector('.dlg.open').focus();
} }
}, true); }, true);
window.openOverlay = function(dlg, primaryContent, body) {
primaryContent.setAttribute('aria-hidden', 'true');
body.classList.add('has-overlay');
var type = dlg.getAttribute('data-type');
if (type) {
body.classList.add('is-' + type + '-dlg');
}
dlg.removeAttribute('aria-hidden');
dlg.setAttribute('role', 'alertdialog');
dlg.setAttribute('tabindex', '0');
dlg.focus();
setTimeout(function() { dlg.classList.add('open'); }, 100);
}
window.closeOverlay = function(dlg, primaryContent, body) {
setTimeout(function() {
body.classList.remove('has-overlay');
body.removeAttribute('style');
}, 250);
var type = dlg.getAttribute('data-type');
if (type) {
body.classList.remove('is-' + type + '-dlg');
}
primaryContent.removeAttribute('aria-hidden');
dlg.setAttribute('aria-hidden', 'true');
dlg.removeAttribute('tabindex');
dlg.classList.remove('open');
dlg.removeAttribute('role');
}
function openDlg(dlg, link) { function openDlg(dlg, link) {
document.getElementById('overlay').onclick =
dlg.querySelector('.close').onclick = function() { closeDlg(dlg); };
body.setAttribute('style', 'width: ' + body.clientWidth + 'px'); body.setAttribute('style', 'width: ' + body.clientWidth + 'px');
var msg = link.querySelector('.message'); var msg = link.querySelector('.message');
if (msg) { if (msg) {
@ -61,27 +92,12 @@
} }
}); });
} }
primaryContent.setAttribute('aria-hidden', 'true'); window.openOverlay(dlg, primaryContent, body);
document.getElementById('overlay').onclick =
dlg.querySelector('.close').onclick = function() { console.log('overlay'); closeDlg(dlg); };
body.classList.add('has-overlay');
dlg.removeAttribute('aria-hidden');
dlg.setAttribute('role', 'alertdialog');
dlg.setAttribute('tabindex', '0');
dlg.focus();
setTimeout(function() { dlg.classList.add('open'); }, 100);
} }
function closeDlg(dlg) { function closeDlg(dlg) {
setTimeout(function() { window.closeOverlay(dlg, primaryContent, body);
body.classList.remove('has-overlay');
body.removeAttribute('style');
}, 250);
primaryContent.removeAttribute('aria-hidden');
dlg.setAttribute('aria-hidden', 'true');
dlg.removeAttribute('tabindex');
dlg.classList.remove('open');
dlg.removeAttribute('role');
} }
var confirmationDlg = document.getElementById('confirmation-dlg'); var confirmationDlg = document.getElementById('confirmation-dlg');
forEachElement('[data-confirmation]', function(link) { forEachElement('[data-confirmation]', function(link) {
link.addEventListener('click', function(event) { link.addEventListener('click', function(event) {

367
app/assets/stylesheets/_application.scss

@ -1543,6 +1543,7 @@ table.schedule {
margin: 0 0 1em; margin: 0 0 1em;
td { td {
position: relative;
text-align: center; text-align: center;
&.empty { &.empty {
@ -1571,6 +1572,25 @@ table.schedule {
@include font-family(secondary); @include font-family(secondary);
} }
.event-detail-link {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
color: inherit;
@include after {
display: none;
}
&:hover {
outline: 0.33rem solid #02CA9E;
outline-offset: 0.25rem;
z-index: 1;
}
}
.status { .status {
display: inline-block; display: inline-block;
text-align: left; text-align: left;
@ -1621,6 +1641,7 @@ table.schedule {
} }
} }
#main .columns & form { #main .columns & form {
margin-top: 0; margin-top: 0;
@ -1632,10 +1653,45 @@ table.schedule {
} }
} }
.event-dlg {
@include _-(flex, 0);
position: relative;
z-index: 1000;
background-color: $white;
text-align: left;
padding: 2em 2em 0.5em;
min-width: 100%;
max-height: 100%;
overflow: auto;
margin: auto;
@include _(opacity, 0);
@include _(transition, opacity 150ms ease-in-out);
@include default-box-shadow(top, 2);
.actions {
margin: 2em 0 0;
}
&.open {
@include _(opacity, 1);
}
}
.event-details {
.title {
margin: 0 0 0.5em;
}
.address {
text-align: center;
}
}
#admin-schedule { #admin-schedule {
.workshop-list { .workshops-to-schedule {
@include _-(display, flex); @include _-(display, flex);
@include _(flex-wrap, wrap); @include _(flex-wrap, wrap);
list-style: none;
padding: 0; padding: 0;
li { li {
@ -1643,6 +1699,7 @@ table.schedule {
@include _(flex-basis, 48%); @include _(flex-basis, 48%);
margin: 1%; margin: 1%;
@include _(transition, background-color 250ms ease-in-out); @include _(transition, background-color 250ms ease-in-out);
background-color: #EEE;
.title { .title {
@include _(transition, background-color 250ms ease-in-out); @include _(transition, background-color 250ms ease-in-out);
@ -1690,6 +1747,26 @@ table.schedule {
margin: 0 5% 1em; margin: 0 5% 1em;
width: 90%; width: 90%;
} }
.title {
margin: 0 0 0.5em;
padding: 0.5em;
background-color: $black;
color: $white;
}
.drop-downs {
padding: 0 1em 1em;
select {
width: 100%;
}
}
.actions {
margin: 0;
padding: 0 0.5em;
}
} }
#main .columns & form { #main .columns & form {
@ -2126,6 +2203,15 @@ body {
display: block; display: block;
} }
body.has-overlay.is-event-dlg & {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
@include _-(display, flex);
}
.dlg { .dlg {
@include before { @include before {
content: ''; content: '';
@ -2167,21 +2253,23 @@ body {
@include _(transform-origin, center 250%); @include _(transform-origin, center 250%);
} }
.title { .dlg {
padding: 0.5em; .title {
background-color: $colour-5; padding: 0.5em;
color: $white; background-color: $colour-5;
@include _(text-stroke, 1px rgba(0, 0, 0, 0.25)); color: $white;
} @include _(text-stroke, 1px rgba(0, 0, 0, 0.25));
}
.dlg-inner {
padding: 0 2em 2em;
} }
button, .button { button, .button {
margin: 0 0.25em 0.5em; margin: 0 0.25em 0.5em;
} }
.dlg-inner {
padding: 0 2em 2em;
}
.message { .message {
margin-bottom: 2em; margin-bottom: 2em;
} }
@ -2808,23 +2896,6 @@ html[data-lingua-franca-example="html"] {
&:last-child { &:last-child {
border: 0; border: 0;
} }
// &:hover {
// @include default-box-shadow;
// }
&.interested {
.workshop-interest {
// background-color: rgba($colour-5, 0.5);
}
}
&.mine {
.workshop-interest {
// background-color: lighten($colour-1, 25%);
// background-color: rgba($colour-1, 0.5);
}
}
} }
.actions { .actions {
@ -2845,28 +2916,22 @@ html[data-lingua-franca-example="html"] {
font-size: 1em; font-size: 1em;
} }
.workshop-interest {
// padding: 0.5em 1em;
// font-weight: bold;
// background-color: #EEE;
}
.interest-button {
button {
margin: 0 0 0 1em;
font-size: 0.8em;
padding-top: 0.333em;
padding-bottom: 0.333em;
background-color: $colour-5;
}
}
h5, h6 { h5, h6 {
margin: 1em 0 0; margin: 1em 0 0;
} }
} }
#main .workshop-interest { .interest-button {
button {
margin: 0 0 0 1em;
font-size: 0.8em;
padding-top: 0.333em;
padding-bottom: 0.333em;
background-color: $colour-5;
}
}
#main .workshop-interest, .workshop-interest {
text-align: right; text-align: right;
form { form {
@ -3073,116 +3138,116 @@ html[data-lingua-franca-example="html"] {
} }
} }
.programme { // .programme {
.schedule { // .schedule {
width: auto; // width: auto;
margin: 0; // margin: 0;
min-width: 100%; // min-width: 100%;
@include _(box-shadow, none); // @include _(box-shadow, none);
table-layout: fixed; // table-layout: fixed;
border-spacing: 0.25em; // border-spacing: 0.25em;
border-collapse: separate; // border-collapse: separate;
td { // td {
position: relative; // position: relative;
vertical-align: middle; // vertical-align: middle;
.title { // .title {
text-align: center; // text-align: center;
@include font-family(secondary); // @include font-family(secondary);
color: #666; // color: #666;
} // }
&.previewable { // &.previewable {
cursor: pointer; // cursor: pointer;
&:hover { // &:hover {
@include default-box-shadow(top, 2); // @include default-box-shadow(top, 2);
} // }
} // }
&.workshop { // &.workshop {
background-color: lighten($colour-1, 35); // background-color: lighten($colour-1, 35);
border: 0.25em solid $colour-1; // border: 0.25em solid $colour-1;
.preview { // .preview {
position: absolute; // position: absolute;
top: 0; // top: 0;
right: 0; // right: 0;
bottom: 0; // bottom: 0;
left: 0; // left: 0;
@include after { // @include after {
display: none; // display: none;
} // }
} // }
} // }
&.event { // &.event {
background-color: lighten($colour-5, 35); // background-color: lighten($colour-5, 35);
border: 0.25em solid $colour-5; // border: 0.25em solid $colour-5;
} // }
&.meal { // &.meal {
background-color: lighten($colour-3, 25); // background-color: lighten($colour-3, 25);
border: 0.25em solid $colour-3; // border: 0.25em solid $colour-3;
} // }
&.not-interested { // &.not-interested {
.title { // .title {
opacity: 0.5; // opacity: 0.5;
} // }
} // }
.info { // .info {
position: fixed; // position: fixed;
top: 0; // top: 0;
right: 0; // right: 0;
bottom: 0; // bottom: 0;
left: 0; // left: 0;
z-index: 1000; // z-index: 1000;
background-color: $white; // background-color: $white;
text-align: left; // text-align: left;
overflow-y: auto; // overflow-y: auto;
@include _(transition, transform 250ms ease-in-out); // @include _(transition, transform 250ms ease-in-out);
@include _(transform-origin, center bottom); // @include _(transform-origin, center bottom);
@include _(transform, rotate(180deg) translate3d(0, 0, 0)); // @include _(transform, rotate(180deg) translate3d(0, 0, 0));
.close { // .close {
float: right; // float: right;
font-size: 2em; // font-size: 2em;
@include before { // @include before {
content: '×'; // content: '×';
padding: 0 0.5em; // padding: 0 0.5em;
} // }
@include after { // @include after {
display: none; // display: none;
} // }
} // }
h2 { // h2 {
margin-bottom: 0.5em; // margin-bottom: 0.5em;
} // }
} // }
&:target .info { // &:target .info {
@include _(transform, rotate(0) translate3d(0, 0, 0)); // @include _(transform, rotate(0) translate3d(0, 0, 0));
} // }
} // }
} // }
.programme-day { // .programme-day {
margin-top: 2em; // margin-top: 2em;
} // }
.programme-day-part { // .programme-day-part {
overflow-x: auto; // overflow-x: auto;
} // }
} // }
.select-field { .select-field {
line-height: 1.75em; line-height: 1.75em;
@ -3528,6 +3593,10 @@ html[data-ontop] {
padding: 0 2em; padding: 0 2em;
} }
.event-dlg {
min-width: 75%;
}
#main { #main {
clear: right; clear: right;

197
app/controllers/application_controller.rb

@ -67,14 +67,17 @@ class ApplicationController < LinguaFrancaApplicationController
@workshops = Workshop.where(:conference_id => @conference.id) @workshops = Workshop.where(:conference_id => @conference.id)
if @conference.workshop_schedule_published if @conference.workshop_schedule_published
@events = Event.where(:conference_id => @conference.id) @event_dlg = true
schedule = get_schedule_data view_context.add_inline_script :schedule
@schedule = schedule[:schedule] get_scheule_data#(false)
@locations = Hash.new # @events = Event.where(:conference_id => @conference.id)
EventLocation.where(:conference_id => @conference.id).each do |l| # schedule = get_schedule_data
@locations[l.id.to_s] = l # @schedule = schedule[:schedule]
end # @locations = Hash.new
@day_parts = @conference.day_parts ? JSON.parse(@conference.day_parts) : {:morning => 0, :afternoon => 13, :evening => 18} # EventLocation.where(:conference_id => @conference.id).each do |l|
# @locations[l.id.to_s] = l
# end
# @day_parts = @conference.day_parts ? JSON.parse(@conference.day_parts) : {:morning => 0, :afternoon => 13, :evening => 18}
end end
end end
@ -444,4 +447,182 @@ class ApplicationController < LinguaFrancaApplicationController
logger.info exception2.backtrace.join("\n") logger.info exception2.backtrace.join("\n")
end end
end end
def get_block_data
conference = @this_conference || @conference
@workshop_blocks = conference.workshop_blocks || []
@block_days = []
day = conference.start_date
while day <= conference.end_date
@block_days << day.wday
day += 1.day
end
end
def get_scheule_data(do_analyze = true)
conference = @this_conference || @conference
@meals = Hash[conference.meals.map{ |k, v| [k.to_i, v] }].sort.to_h
@events = Event.where(:conference_id => conference.id).order(start_time: :asc)
@workshops = Workshop.where(:conference_id => conference.id).order(start_time: :asc)
@locations = {}
get_block_data
@schedule = {}
day_1 = conference.start_date.wday
@workshop_blocks.each_with_index do | info, block |
info['days'].each do | block_day |
day_diff = block_day.to_i - day_1
day_diff += 7 if day_diff < 0
day = (conference.start_date + day_diff.days).to_date
time = info['time'].to_f
@schedule[day] ||= { times: {}, locations: {} }
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :workshop
@schedule[day][:times][time][:length] = info['length'].to_f
@schedule[day][:times][time][:item] = { block: block, workshops: {} }
end
end
@workshops.each do | workshop |
if workshop.block.present?
block = @workshop_blocks[workshop.block['block'].to_i]
day_diff = workshop.block['day'].to_i - day_1
day_diff += 7 if day_diff < 0
day = (conference.start_date + day_diff.days).to_date
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
end
end
end
@meals.each do | time, meal |
day = meal['day'].to_date
time = meal['time'].to_f
@schedule[day] ||= {}
@schedule[day][:times] ||= {}
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :meal
@schedule[day][:times][time][:length] = (meal['length'] || 1.0).to_f
@schedule[day][:times][time][:item] = meal
end
@events.each do | event |
day = event.start_time.midnight.to_date
time = event.start_time.hour.to_f + (event.start_time.min / 60.0)
@schedule[day] ||= {}
@schedule[day][:times] ||= {}
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :event
@schedule[day][:times][time][:length] = (event.end_time - event.start_time) / 3600.0
@schedule[day][:times][time][:item] = event
end
@schedule = @schedule.sort.to_h
@schedule.each do | day, data |
@schedule[day][:times] = data[:times].sort.to_h
end
@schedule.each do | day, data |
last_event = nil
data[:times].each do | time, time_data |
if last_event.present?
@schedule[day][:times][last_event][:next_event] = time
end
last_event = time
end
end
@schedule.deep_dup.each do | day, data |
data[:times].each do | time, time_data |
if time_data[:next_event].present? || time_data[:length] > 0.5
span = 0.5
length = time_data[:next_event].present? ? time_data[:next_event] - time : time_data[:length]
while span < length
@schedule[day][:times][time + span] ||= {
type: (span >= time_data[:length] ? :empty : :nil),
length: 0.5
}
span += 0.5
end
end
end
end
@schedule = @schedule.sort.to_h
return unless do_analyze
@schedule.each do | day, data |
@schedule[day][:times] = data[:times].sort.to_h
data[:times].each do | time, time_data |
if time_data[:type] == :workshop && time_data[:item].present? && time_data[:item][:workshops].present?
ids = time_data[:item][:workshops].keys
(0..ids.length).each do | i |
if time_data[:item][:workshops][ids[i]].present?
workshop_i = time_data[:item][:workshops][ids[i]][:workshop]
conflicts = {}
(i+1..ids.length).each do | j |
workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil
if workshop_i.present? && workshop_j.present?
workshop_i.active_facilitators.each do | facilitator_i |
workshop_j.active_facilitators.each do | facilitator_j |
if facilitator_i.id == facilitator_j.id
@schedule[day][:times][time][:status] ||= {}
@schedule[day][:times][time][:item][:workshops][ids[j]][:status][:errors] << {
name: :common_facilitator,
facilitator: facilitator_i,
workshop: workshop_i,
i18nVars: {
facilitator_name: facilitator_i.name,
workshop_title: workshop_i.title
}
}
end
end
end
end
end
(0..ids.length).each do | j |
workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil
if workshop_i.present? && workshop_j.present? && workshop_i.id != workshop_j.id
workshop_i.interested.each do | interested_i |
workshop_j.interested.each do | interested_j |
conflicts[interested_i.id] ||= true
end
end
end
end
needs = JSON.parse(workshop_i.needs || '[]').map &:to_sym
amenities = JSON.parse(workshop_i.event_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,
workshop: workshop_i,
i18nVars: {
need: need.to_s,
location: workshop_i.event_location.title,
workshop_title: workshop_i.title
}
} unless amenities.include? need
end
@schedule[day][:times][time][:item][:workshops][ids[i]][:status][:conflict_score] = workshop_i.interested.present? ? (conflicts.length / workshop_i.interested.size) : 0
end
end
end
end
end
end
end end

710
app/controllers/conferences_controller.rb

@ -743,6 +743,7 @@ class ConferencesController < ApplicationController
case @admin_step.to_sym case @admin_step.to_sym
when :stats when :stats
@registrations = ConferenceRegistration.where(:conference_id => @this_conference.id) @registrations = ConferenceRegistration.where(:conference_id => @this_conference.id)
if request.format.xlsx? if request.format.xlsx?
logger.info "Generating stats.xls" logger.info "Generating stats.xls"
@excel_data = { @excel_data = {
@ -773,6 +774,23 @@ class ConferencesController < ApplicationController
# format.html # format.html
format.xlsx { render xlsx: :stats, filename: "stats-#{DateTime.now.strftime('%Y-%m-%d')}" } format.xlsx { render xlsx: :stats, filename: "stats-#{DateTime.now.strftime('%Y-%m-%d')}" }
end end
else
@registration_count = @registrations.size
@bikes = @registrations.count { |r| r.bike == 'yes' }
@donation_count =0
@donations = 0
@food = { meat: 0, vegan: 0, vegetarian: 0, all: 0 }
@registrations.each do | r |
if r.food.present?
@food[r.food.to_sym] += 1
@food[:all] += 1
end
if r.registration_fees_paid.present? && r.registration_fees_paid > 0
@donation_count += 1
@donations += r.registration_fees_paid
end
end
end end
when :housing when :housing
# do a full analysis # do a full analysis
@ -795,6 +813,8 @@ class ConferencesController < ApplicationController
'days' => [] 'days' => []
} }
when :schedule when :schedule
@can_edit = true
@entire_page = true
get_scheule_data get_scheule_data
end end
when :done when :done
@ -803,178 +823,6 @@ class ConferencesController < ApplicationController
end end
def get_block_data
@workshop_blocks = @this_conference.workshop_blocks || []
@block_days = []
day = @this_conference.start_date
while day <= @this_conference.end_date
@block_days << day.wday
day += 1.day
end
end
def get_scheule_data
@meals = Hash[@this_conference.meals.map{ |k, v| [k.to_i, v] }].sort.to_h
@events = Event.where(:conference_id => @this_conference.id).order(start_time: :asc)
@workshops = Workshop.where(:conference_id => @this_conference.id).order(start_time: :asc)
@locations = {}
get_block_data
@schedule = {}
day_1 = @this_conference.start_date.wday
@workshop_blocks.each_with_index do | info, block |
info['days'].each do | block_day |
day_diff = block_day.to_i - day_1
day_diff += 7 if day_diff < 0
day = (@this_conference.start_date + day_diff.days).to_date
time = info['time'].to_f
@schedule[day] ||= { times: {}, locations: {} }
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :workshop
@schedule[day][:times][time][:length] = info['length'].to_f
@schedule[day][:times][time][:item] = { block: block, workshops: {} }
end
end
@workshops.each do | workshop |
if workshop.block.present?
block = @workshop_blocks[workshop.block['block'].to_i]
day_diff = workshop.block['day'].to_i - day_1
day_diff += 7 if day_diff < 0
day = (@this_conference.start_date + day_diff.days).to_date
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
end
end
end
@meals.each do | time, meal |
day = meal['day'].to_date
time = meal['time'].to_f
@schedule[day] ||= {}
@schedule[day][:times] ||= {}
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :meal
@schedule[day][:times][time][:length] = (meal['length'] || 1.0).to_f
@schedule[day][:times][time][:item] = meal
end
@events.each do | event |
day = event.start_time.midnight.to_date
time = event.start_time.hour.to_f + (event.start_time.min / 60.0)
@schedule[day] ||= {}
@schedule[day][:times] ||= {}
@schedule[day][:times][time] ||= {}
@schedule[day][:times][time][:type] = :event
@schedule[day][:times][time][:length] = (event.end_time - event.start_time) / 3600.0
@schedule[day][:times][time][:item] = event
end
@schedule = @schedule.sort.to_h
@schedule.each do | day, data |
@schedule[day][:times] = data[:times].sort.to_h
end
@schedule.each do | day, data |
last_event = nil
data[:times].each do | time, time_data |
if last_event.present?
@schedule[day][:times][last_event][:next_event] = time
end
last_event = time
end
end
@schedule.deep_dup.each do | day, data |
data[:times].each do | time, time_data |
if time_data[:next_event].present? || time_data[:length] > 0.5
span = 0.5
length = time_data[:next_event].present? ? time_data[:next_event] - time : time_data[:length]
while span < length
@schedule[day][:times][time + span] ||= {
type: (span >= time_data[:length] ? :empty : :nil),
length: 0.5
}
span += 0.5
end
end
end
end
@schedule = @schedule.sort.to_h
@schedule.each do | day, data |
@schedule[day][:times] = data[:times].sort.to_h
data[:times].each do | time, time_data |
if time_data[:type] == :workshop && time_data[:item].present? && time_data[:item][:workshops].present?
ids = time_data[:item][:workshops].keys
(0..ids.length).each do | i |
if time_data[:item][:workshops][ids[i]].present?
workshop_i = time_data[:item][:workshops][ids[i]][:workshop]
conflicts = {}
(i+1..ids.length).each do | j |
workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil
if workshop_i.present? && workshop_j.present?
workshop_i.active_facilitators.each do | facilitator_i |
workshop_j.active_facilitators.each do | facilitator_j |
if facilitator_i.id == facilitator_j.id
@schedule[day][:times][time][:status] ||= {}
@schedule[day][:times][time][:item][:workshops][ids[j]][:status][:errors] << {
name: :common_facilitator,
facilitator: facilitator_i,
workshop: workshop_i,
i18nVars: {
facilitator_name: facilitator_i.name,
workshop_title: workshop_i.title
}
}
end
end
end
end
end
(0..ids.length).each do | j |
workshop_j = time_data[:item][:workshops][ids[j]].present? ? time_data[:item][:workshops][ids[j]][:workshop] : nil
if workshop_i.present? && workshop_j.present? && workshop_i.id != workshop_j.id
workshop_i.interested.each do | interested_i |
workshop_j.interested.each do | interested_j |
conflicts[interested_i.id] ||= true
end
end
end
end
needs = JSON.parse(workshop_i.needs || '[]').map &:to_sym
amenities = JSON.parse(workshop_i.event_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,
workshop: workshop_i,
i18nVars: {
need: need.to_s,
location: workshop_i.event_location.title,
workshop_title: workshop_i.title
}
} unless amenities.include? need
end
@schedule[day][:times][time][:item][:workshops][ids[i]][:status][:conflict_score] = workshop_i.interested.present? ? (conflicts.length / workshop_i.interested.size) : 0
end
end
end
end
end
end
def get_housing_data def get_housing_data
@hosts = {} @hosts = {}
@guests = {} @guests = {}
@ -1290,10 +1138,16 @@ class ConferencesController < ApplicationController
workshop.block = nil workshop.block = nil
workshop.save! workshop.save!
success = true success = true
when 'publish'
@this_conference.workshop_schedule_published = !@this_conference.workshop_schedule_published
@this_conference.save
return redirect_to administration_step_path(@this_conference.slug, :schedule)
end end
if success if success
if request.xhr? if request.xhr?
@can_edit = true
@entire_page = false
get_scheule_data get_scheule_data
schedule = render_to_string partial: 'conferences/admin/schedule' schedule = render_to_string partial: 'conferences/admin/schedule'
return render json: [ { return render json: [ {
@ -1314,51 +1168,51 @@ class ConferencesController < ApplicationController
do_404 do_404
end end
def registrations # def registrations
registrations = ConferenceRegistration.where(:conference_id => @conference.id) # registrations = ConferenceRegistration.where(:conference_id => @conference.id)
@registrations = registrations # @registrations = registrations
end # end
def register_confirm # def register_confirm
set_conference # set_conference
@conference_registration = ConferenceRegistration.find_by(confirmation_token: params[:confirmation_token]) # @conference_registration = ConferenceRegistration.find_by(confirmation_token: params[:confirmation_token])
if !@conference_registration.nil? && @conference_registration.conference_id == @conference.id && !@conference_registration.complete # if !@conference_registration.nil? && @conference_registration.conference_id == @conference.id && !@conference_registration.complete
@conference_registration.is_confirmed = true # @conference_registration.is_confirmed = true
@conference_registration.save! # @conference_registration.save!
session[:registration] = YAML.load(@conference_registration.data) # session[:registration] = YAML.load(@conference_registration.data)
session[:registration][:path] = Array.new # session[:registration][:path] = Array.new
session[:registration][:registration_id] = @conference_registration.id # session[:registration][:registration_id] = @conference_registration.id
session[:registration_step] = 'confirm' # session[:registration_step] = 'confirm'
redirect_to action: 'register' # redirect_to action: 'register'
else # else
return do_404 # return do_404
end # end
end # end
def register_pay_registration # def register_pay_registration
set_conference # set_conference
@conference_registration = ConferenceRegistration.find_by(confirmation_token: params[:confirmation_token]) # @conference_registration = ConferenceRegistration.find_by(confirmation_token: params[:confirmation_token])
host = "#{request.protocol}#{request.host_with_port}" # host = "#{request.protocol}#{request.host_with_port}"
if !@conference_registration.nil? && @conference_registration.conference_id == @conference.id && @conference_registration.complete # if !@conference_registration.nil? && @conference_registration.conference_id == @conference.id && @conference_registration.complete
amount = (params[:auto_payment_amount] || params[:payment_amount]).to_f # amount = (params[:auto_payment_amount] || params[:payment_amount]).to_f
if amount > 0 # if amount > 0
response = PayPal!.setup( # response = PayPal!.setup(
PayPalRequest(amount), # PayPalRequest(amount),
host + (@conference.url + "/register/paypal-confirm/#{@conference_registration.payment_confirmation_token}/").gsub(/\/\/+/, '/'), # host + (@conference.url + "/register/paypal-confirm/#{@conference_registration.payment_confirmation_token}/").gsub(/\/\/+/, '/'),
host + (@conference.url + "/register/paypal-cancel/#{@conference_registration.confirmation_token}/").gsub(/\/\/+/, '/') # host + (@conference.url + "/register/paypal-cancel/#{@conference_registration.confirmation_token}/").gsub(/\/\/+/, '/')
) # )
redirect_to response.redirect_uri # redirect_to response.redirect_uri
else # else
session[:registration] = YAML.load(@conference_registration.data) # session[:registration] = YAML.load(@conference_registration.data)
session[:registration][:registration_id] = @conference_registration.id # session[:registration][:registration_id] = @conference_registration.id
session[:registration][:path] = Array.new # session[:registration][:path] = Array.new
session[:registration_step] = 'pay_now' # session[:registration_step] = 'pay_now'
redirect_to action: 'register' # redirect_to action: 'register'
end # end
else # else
return do_404 # return do_404
end # end
end # end
# def register_paypal_confirm # def register_paypal_confirm
# set_conference # set_conference
@ -1776,261 +1630,261 @@ class ConferencesController < ApplicationController
return redirect_to view_workshop_url(@this_conference.slug, workshop.id, anchor: "comment-#{new_comment.id}") return redirect_to view_workshop_url(@this_conference.slug, workshop.id, anchor: "comment-#{new_comment.id}")
end end
def schedule # def schedule
set_conference # set_conference
return do_404 unless @this_conference.workshop_schedule_published || @this_conference.host?(current_user) # return do_404 unless @this_conference.workshop_schedule_published || @this_conference.host?(current_user)
@events = Event.where(:conference_id => @this_conference.id).order(start_time: :asc) # @events = Event.where(:conference_id => @this_conference.id).order(start_time: :asc)
@locations = EventLocation.where(:conference_id => @this_conference.id) # @locations = EventLocation.where(:conference_id => @this_conference.id)
render 'schedule/show' # render 'schedule/show'
end # end
def edit_schedule # def edit_schedule
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
@workshops = Workshop.where(:conference_id => @this_conference.id) # @workshops = Workshop.where(:conference_id => @this_conference.id)
@events = Event.where(:conference_id => @this_conference.id) # @events = Event.where(:conference_id => @this_conference.id)
if session[:workshops] # if session[:workshops]
(0...@workshops.count).each do |i| # (0...@workshops.count).each do |i|
id = @workshops[i].id # id = @workshops[i].id
w = session[:workshops][id.to_s] # w = session[:workshops][id.to_s]
if w # if w
@workshops[i].start_time = w[:start_time] # @workshops[i].start_time = w[:start_time]
@workshops[i].end_time = w[:end_time] # @workshops[i].end_time = w[:end_time]
@workshops[i].event_location_id = w[:event_location_id] # @workshops[i].event_location_id = w[:event_location_id]
end # end
end # end
end # end
if session[:events] # if session[:events]
(0...@events.count).each do |i| # (0...@events.count).each do |i|
id = @events[i].id # id = @events[i].id
w = session[:events][id.to_s] # w = session[:events][id.to_s]
if w # if w
@events[i].start_time = w[:start_time] # @events[i].start_time = w[:start_time]
@events[i].end_time = w[:end_time] # @events[i].end_time = w[:end_time]
@events[i].event_location_id = w[:event_location_id] # @events[i].event_location_id = w[:event_location_id]
end # end
end # end
end # end
@locations = EventLocation.where(:conference_id => @this_conference.id) # @locations = EventLocation.where(:conference_id => @this_conference.id)
@location_hash = Hash.new # @location_hash = Hash.new
@locations.each do |l| # @locations.each do |l|
@location_hash[l.id.to_s] = l # @location_hash[l.id.to_s] = l
end # end
@days = Array.new # @days = Array.new
start_day = @this_conference.start_date.strftime('%u').to_i # start_day = @this_conference.start_date.strftime('%u').to_i
end_day = start_day + ((@this_conference.end_date - @this_conference.start_date) / 86400) # end_day = start_day + ((@this_conference.end_date - @this_conference.start_date) / 86400)
(start_day..end_day).each do |i| # (start_day..end_day).each do |i|
@days << [(@this_conference.start_date + (i - start_day).days).strftime('%a'), ((i + 1) - start_day)] # @days << [(@this_conference.start_date + (i - start_day).days).strftime('%a'), ((i + 1) - start_day)]
end # end
@hours = Array.new # @hours = Array.new
(0..48).each do |i| # (0..48).each do |i|
hour = (Date.today + (i / 2.0).hours).strftime('%R') # hour = (Date.today + (i / 2.0).hours).strftime('%R')
@hours << hour # @hours << hour
end # end
@event_durations = [['30 mins', 30], ['1 hour', 60], ['1.5 hours', 90], ['2 hours', 120], ['2.5 hours', 150]] # @event_durations = [['30 mins', 30], ['1 hour', 60], ['1.5 hours', 90], ['2 hours', 120], ['2.5 hours', 150]]
@workshop_durations = [['1 hour', 60], ['1.5 hours', 90], ['2 hours', 120]] # @workshop_durations = [['1 hour', 60], ['1.5 hours', 90], ['2 hours', 120]]
schedule_data = get_schedule_data # schedule_data = get_schedule_data
@schedule = schedule_data[:schedule] # @schedule = schedule_data[:schedule]
@errors = schedule_data[:errors] # @errors = schedule_data[:errors]
@warnings = schedule_data[:warnings] # @warnings = schedule_data[:warnings]
@conflict_score = schedule_data[:conflict_score] # @conflict_score = schedule_data[:conflict_score]
@error_count = schedule_data[:error_count] # @error_count = schedule_data[:error_count]
if session[:day_parts] # if session[:day_parts]
@day_parts = JSON.parse(session[:day_parts]) # @day_parts = JSON.parse(session[:day_parts])
elsif @this_conference.day_parts # elsif @this_conference.day_parts
@day_parts = JSON.parse(@this_conference.day_parts) # @day_parts = JSON.parse(@this_conference.day_parts)
else # else
@day_parts = {:morning => 0, :afternoon => 13, :evening => 18} # @day_parts = {:morning => 0, :afternoon => 13, :evening => 18}
end # end
@saved = session[:workshops].nil? # @saved = session[:workshops].nil?
render 'schedule/edit' # render 'schedule/edit'
end # end
def save_schedule # def save_schedule
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
@days = Array.new # @days = Array.new
start_day = @this_conference.start_date.strftime('%u').to_i # start_day = @this_conference.start_date.strftime('%u').to_i
end_day = start_day + ((@this_conference.end_date - @this_conference.start_date) / 86400) # end_day = start_day + ((@this_conference.end_date - @this_conference.start_date) / 86400)
(start_day..end_day).each do |i| # (start_day..end_day).each do |i|
@days << [(@this_conference.start_date + (i - start_day).days).strftime('%a'), i] # @days << [(@this_conference.start_date + (i - start_day).days).strftime('%a'), i]
end # end
@workshops = Workshop.where(:conference_id => @this_conference.id) # @workshops = Workshop.where(:conference_id => @this_conference.id)
@events = Event.where(:conference_id => @this_conference.id) # @events = Event.where(:conference_id => @this_conference.id)
@locations = EventLocation.where(:conference_id => @this_conference.id) # @locations = EventLocation.where(:conference_id => @this_conference.id)
do_save = (params[:button] == 'save' || params[:button] == 'publish') # do_save = (params[:button] == 'save' || params[:button] == 'publish')
session[:workshops] = do_save ? nil : Hash.new # session[:workshops] = do_save ? nil : Hash.new
session[:events] = do_save ? nil : Hash.new # session[:events] = do_save ? nil : Hash.new
session[:day_parts] = do_save ? nil : Hash.new # session[:day_parts] = do_save ? nil : Hash.new
(0...@workshops.count).each do |i| # (0...@workshops.count).each do |i|
id = @workshops[i].id.to_s # id = @workshops[i].id.to_s
if params[:workshop_day][id].present? && params[:workshop_hour][id].present? && params[:workshop_duration][id].present? # if params[:workshop_day][id].present? && params[:workshop_hour][id].present? && params[:workshop_duration][id].present?
date = @this_conference.start_date + (params[:workshop_day][id].to_i - 1).days # date = @this_conference.start_date + (params[:workshop_day][id].to_i - 1).days
h = params[:workshop_hour][id].split(':') # h = params[:workshop_hour][id].split(':')
date = date.change({hour: h.first, minute: h.last}) # date = date.change({hour: h.first, minute: h.last})
@workshops[i].start_time = date # @workshops[i].start_time = date
@workshops[i].end_time = date + (params[:workshop_duration][id].to_i).minutes # @workshops[i].end_time = date + (params[:workshop_duration][id].to_i).minutes
else # else
@workshops[i].start_time = nil # @workshops[i].start_time = nil
@workshops[i].end_time = nil # @workshops[i].end_time = nil
end # end
@workshops[i].event_location_id = params[:workshop_location][id] # @workshops[i].event_location_id = params[:workshop_location][id]
if do_save # if do_save
@workshops[i].save # @workshops[i].save
else # else
session[:workshops][id] = { # session[:workshops][id] = {
:start_time => @workshops[i].start_time, # :start_time => @workshops[i].start_time,
:end_time => @workshops[i].end_time, # :end_time => @workshops[i].end_time,
:event_location_id => @workshops[i].event_location_id # :event_location_id => @workshops[i].event_location_id
} # }
end # end
end # end
(0...@events.count).each do |i| # (0...@events.count).each do |i|
id = @events[i].id.to_s # id = @events[i].id.to_s
if params[:event_day][id].present? && params[:event_hour][id].present? && params[:event_duration][id].present? # if params[:event_day][id].present? && params[:event_hour][id].present? && params[:event_duration][id].present?
date = @this_conference.start_date + (params[:event_day][id].to_i - 1).days # date = @this_conference.start_date + (params[:event_day][id].to_i - 1).days
h = params[:event_hour][id].split(':') # h = params[:event_hour][id].split(':')
date = date.change({hour: h.first, minute: h.last}) # date = date.change({hour: h.first, minute: h.last})
@events[i].start_time = date # @events[i].start_time = date
@events[i].end_time = date + (params[:event_duration][id].to_i).minutes # @events[i].end_time = date + (params[:event_duration][id].to_i).minutes
else # else
@events[i].start_time = nil # @events[i].start_time = nil
@events[i].end_time = nil # @events[i].end_time = nil
end # end
@events[i].event_location_id = params[:event_location][id] # @events[i].event_location_id = params[:event_location][id]
if do_save # if do_save
@events[i].save # @events[i].save
else # else
session[:events][id] = { # session[:events][id] = {
:start_time => @events[i].start_time, # :start_time => @events[i].start_time,
:end_time => @events[i].end_time, # :end_time => @events[i].end_time,
:event_location_id => @events[i].event_location_id # :event_location_id => @events[i].event_location_id
} # }
end # end
end # end
if params[:day_parts] # if params[:day_parts]
day_parts = {:morning => 0} # day_parts = {:morning => 0}
params[:day_parts].each do |part, h| # params[:day_parts].each do |part, h|
h = h.split(':') # h = h.split(':')
day_parts[part.to_sym] = h[0].to_f + (h[1].to_i > 0 ? 0.5 : 0) # day_parts[part.to_sym] = h[0].to_f + (h[1].to_i > 0 ? 0.5 : 0)
end # end
if do_save # if do_save
@this_conference.day_parts = day_parts.to_json # @this_conference.day_parts = day_parts.to_json
else # else
session[:day_parts] = day_parts.to_json # session[:day_parts] = day_parts.to_json
end # end
end # end
save_conference = do_save # save_conference = do_save
if params[:button] == 'publish' # if params[:button] == 'publish'
@this_conference.workshop_schedule_published = true # @this_conference.workshop_schedule_published = true
save_conference = true # save_conference = true
elsif params[:button] == 'unpublish' # elsif params[:button] == 'unpublish'
@this_conference.workshop_schedule_published = false # @this_conference.workshop_schedule_published = false
save_conference = true # save_conference = true
end # end
if save_conference # if save_conference
@this_conference.save # @this_conference.save
end # end
redirect_to edit_schedule_url(@this_conference.slug) # redirect_to edit_schedule_url(@this_conference.slug)
end # end
def add_event # def add_event
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
render 'events/edit' # render 'events/edit'
end # end
def edit_event # def edit_event
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
@event = Event.find(params[:id]) # @event = Event.find(params[:id])
return do_403 unless @event.conference_id == @this_conference.id # return do_403 unless @event.conference_id == @this_conference.id
render 'events/edit' # render 'events/edit'
end # end
def save_event # def save_event
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
if params[:event_id] # if params[:event_id]
event = Event.find(params[:event_id]) # event = Event.find(params[:event_id])
return do_403 unless event.conference_id == @this_conference.id # return do_403 unless event.conference_id == @this_conference.id
else # else
event = Event.new(:conference_id => @this_conference.id) # event = Event.new(:conference_id => @this_conference.id)
end # end
event.title = params[:title] # event.title = params[:title]
event.info = params[:info] # event.info = params[:info]
event.event_type = params[:event_type] # event.event_type = params[:event_type]
event.save # event.save
return redirect_to schedule_url(@this_conference.slug) # return redirect_to schedule_url(@this_conference.slug)
end # end
def add_location # def add_location
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
render 'event_locations/edit' # render 'event_locations/edit'
end # end
def edit_location # def edit_location
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
@location = EventLocation.find(params[:id]) # @location = EventLocation.find(params[:id])
return do_403 unless @location.conference_id == @this_conference.id # return do_403 unless @location.conference_id == @this_conference.id
@amenities = JSON.parse(@location.amenities || '[]').map &:to_sym # @amenities = JSON.parse(@location.amenities || '[]').map &:to_sym
render 'event_locations/edit' # render 'event_locations/edit'
end # end
def save_location # def save_location
set_conference # set_conference
return do_404 unless @this_conference.host?(current_user) # return do_404 unless @this_conference.host?(current_user)
if params[:location_id] # if params[:location_id]
location = EventLocation.find(params[:location_id]) # location = EventLocation.find(params[:location_id])
return do_403 unless location.conference_id == @this_conference.id # return do_403 unless location.conference_id == @this_conference.id
else # else
location = EventLocation.new(:conference_id => @this_conference.id) # location = EventLocation.new(:conference_id => @this_conference.id)
end # end
location.title = params[:title] # location.title = params[:title]
location.address = params[:address] # location.address = params[:address]
location.amenities = (params[:needs] || {}).keys.to_json # location.amenities = (params[:needs] || {}).keys.to_json
location.save # location.save
return redirect_to schedule_url(@this_conference.slug) # return redirect_to schedule_url(@this_conference.slug)
end # end
# DELETE /conferences/1 # DELETE /conferences/1
#def destroy #def destroy

2
app/models/organization.rb

@ -31,6 +31,8 @@ class Organization < ActiveRecord::Base
def host?(user) def host?(user)
return false unless user.present? return false unless user.present?
return true if user.administrator?
users.each do |u| users.each do |u|
return true if u.id == user.id return true if u.id == user.id
end end

4
app/models/user.rb

@ -36,6 +36,10 @@ class User < ActiveRecord::Base
return "#{name} <#{email}>" return "#{name} <#{email}>"
end end
def administrator?
role == 'administrator'
end
def self.get(email) def self.get(email)
user = where(email: email).first user = where(email: email).first

14
app/views/application/home.html.haml

@ -6,11 +6,11 @@
= columns(medium: 10, push: {medium: 1}) do = columns(medium: 10, push: {medium: 1}) do
%h2=_!@conference.title %h2=_!@conference.title
= @conference.info.html_safe = @conference.info.html_safe
- if @conference.workshops
- if @schedule
%h3=_'articles.workshops.headings.Schedule'
= render 'schedule/programme', :schedule => @schedule, :conference => @conference, :workshops => @workshops, :events => @events, :locations => @locations, :show_interest => true, :day_parts => @day_parts, :show_previews => true
- if @conference.registration_status == :open - if @conference.registration_status == :open
%h3=_'articles.workshops.headings.Proposed_Workshops' - if @conference.workshop_schedule_published
%p=_'articles.workshops.paragraphs.Proposed_Workshops' %h3=_'articles.workshops.headings.Schedule'
= render 'workshops/workshop_previews', :workshops => @conference.workshops = render 'conferences/admin/schedule'
- else
%h3=_'articles.workshops.headings.Proposed_Workshops'
%p=_'articles.workshops.paragraphs.Proposed_Workshops'
= render 'workshops/workshop_previews', :workshops => @conference.workshops

2
app/views/conferences/_questions.html.haml

@ -10,7 +10,7 @@
= selectfield :departure, @registration.departure || @this_conference.start_date, conference_days_options_list(:after) = selectfield :departure, @registration.departure || @this_conference.start_date, conference_days_options_list(:after)
= radiobuttons :bike, ConferenceRegistration.all_bike_options, @registration.bike, 'articles.conference_registration.questions.bike', heading: 'articles.conference_registration.headings.bike', inline: true, big: true = radiobuttons :bike, ConferenceRegistration.all_bike_options, @registration.bike, 'articles.conference_registration.questions.bike', heading: 'articles.conference_registration.headings.bike', inline: true, big: true
= radiobuttons :food, ConferenceRegistration.all_food_options, @registration.food, 'articles.conference_registration.questions.food', heading: 'articles.conference_registration.headings.food', inline: true, big: true = radiobuttons :food, ConferenceRegistration.all_food_options, @registration.food, 'articles.conference_registration.questions.food', heading: 'articles.conference_registration.headings.food', inline: true, big: true
= emailfield :companion, (@registration.housing_data[:companions] || [nil]).first, heading: 'articles.conference_registration.headings.companion', help: 'articles.conference_registration.paragraphs.companion', big: true = emailfield :companion, (@registration.housing_data['companions'] || [nil]).first, heading: 'articles.conference_registration.headings.companion', help: 'articles.conference_registration.paragraphs.companion', big: true
= textfield :allergies, @registration.allergies, heading: 'articles.conference_registration.headings.allergies' = textfield :allergies, @registration.allergies, heading: 'articles.conference_registration.headings.allergies'
= textarea :other, @registration.other, plain: true, heading: 'articles.conference_registration.headings.other' = textarea :other, @registration.other, plain: true, heading: 'articles.conference_registration.headings.other'
= button_tag :register, :value => :questions = button_tag :register, :value => :questions

23
app/views/conferences/admin/_housing.html.haml

@ -20,7 +20,28 @@
%li.guest{id: "guest-#{id}", data: { id: id, 'affected-hosts': @hosts_affected_by_guests[id].join(',') }} %li.guest{id: "guest-#{id}", data: { id: id, 'affected-hosts': @hosts_affected_by_guests[id].join(',') }}
%h4= registration.user.name %h4= registration.user.name
.city=registration.city .city=registration.city
.email.on-top-only=registration.user.email .on-top-only.details
= data_set(:h4, 'articles.admin.housing.headings.email') do
= registration.user.email
= data_set(:h4, 'articles.admin.housing.headings.housing') do
= registration.housing
- if registration.arrival.present?
= data_set(:h4, 'articles.admin.housing.headings.arrival_departure') do
= date_span(registration.arrival.to_date, registration.departure.to_date)
- if (registration.housing_data || {})['companions'].present?
= data_set(:h4, 'articles.admin.housing.headings.companion') do
- companion = User.find_by_email(registration.housing_data['companions'].first)
- if companion
= "#{companion.firstname} (#{companion.email})"
- else
= registration.housing_data['companions'].first
= _'articles.admin.housing.headings.unregistered'
- if registration.allergies.present?
= data_set(:h4, 'articles.admin.housing.headings.allergies') do
= registration.allergies
- if registration.other.present?
= data_set(:h4, 'articles.admin.housing.headings.other') do
= registration.other
= button_tag :set_host, type: :button, class: [:small, 'set-host', 'not-on-top'] = button_tag :set_host, type: :button, class: [:small, 'set-host', 'not-on-top']

82
app/views/conferences/admin/_schedule.html.haml

@ -1,3 +1,13 @@
- 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-preview
- @schedule.each do | day, data | - @schedule.each do | day, data |
%h4=date(day, :weekday) %h4=date(day, :weekday)
@ -24,23 +34,33 @@
- workshop = status = nil - workshop = status = nil
%td{class: [time_data[:type], workshop.present? ? :filled : nil], rowspan: rowspan} %td{class: [time_data[:type], workshop.present? ? :filled : nil], rowspan: rowspan}
- if workshop.present? - if workshop.present?
= form_tag administration_update_path(@this_conference.slug, :schedule), class: 'js-xhr' do = link_to off_screen(workshop.title), view_workshop_path(@conference.slug, workshop.id), class: 'event-detail-link'
.title=workshop.title %template.event-details{data: { href: view_workshop_path(@conference.slug, workshop.id) }}
.status %h1.title=workshop.title
.conflict-score %p.address
%span.title Conflict Score: = workshop.event_location.title + _!(': ')
%span.value="#{status[:conflict_score] * 100.0}%" %a{ href: "http://www.google.com/maps/place/#{workshop.event_location.latitude},#{workshop.event_location.longitude}" }
- if status[:errors].present? = workshop.event_location.address
.errors .workshop-description= richtext workshop.info, 1
- status[:errors].each do | error | .title=workshop.title
.error=_"errors.messages.schedule.#{error[:name].to_s}", vars: error[:i18nVars] - if @can_edit
= hidden_field_tag :id, workshop.id = form_tag administration_update_path(conference.slug, :schedule), class: 'js-xhr' do
= button_tag :deschedule, value: :deschedule_workshop, class: [:delete, :small] .status
- else .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}" .title="Block #{time_data[:item][:block] + 1}"
- else - else
%td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1} %td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1}
.title="Block #{time_data[:item][:block] + 1}" - if @can_edit
.title="Block #{time_data[:item][:block] + 1}"
%td.status{rowspan: rowspan} %td.status{rowspan: rowspan}
- if time_data[:status].present? && time_data[:status][:errors].present? - if time_data[:status].present? && time_data[:status][:errors].present?
%ul.errors %ul.errors
@ -50,18 +70,34 @@
%td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1} %td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1}
- case time_data[:type] - case time_data[:type]
- when :meal - 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'] .title= time_data[:item]['title']
.location= EventLocation.find(time_data[:item]['location'].to_i).title .location= location.title
- when :event - 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 .title= time_data[:item].title
.location= time_data[:item].event_location.title .location= time_data[:item].event_location.title
%td.status{rowspan: rowspan} %td.status{rowspan: rowspan}
- unless request.xhr? - if @entire_page
%ul.workshop-list %ul.workshops-to-schedule
- @workshops.each do | workshop | - @workshops.each do | workshop |
%li{id: "workshop-#{workshop.id}", class: workshop.block.present? ? 'booked' : 'not-booked'} %li{id: "workshop-#{workshop.id}", class: workshop.block.present? ? 'booked' : 'not-booked'}
%h4.title= workshop.title %h4.title= workshop.title
= form_tag administration_update_path(@this_conference.slug, :schedule), class: 'js-xhr' do = form_tag administration_update_path(conference.slug, :schedule), class: 'js-xhr' do
.already-booked .already-booked
.field-error='This block is already booked' .field-error='This block is already booked'
.workshop-description .workshop-description
@ -89,10 +125,10 @@
= link_info_dlg truncate(workshop.notes), (richtext workshop.notes.html_safe), workshop.title = link_info_dlg truncate(workshop.notes), (richtext workshop.notes.html_safe), workshop.title
= hidden_field_tag :id, workshop.id = hidden_field_tag :id, workshop.id
.flex-inputs .drop-downs
= location_select workshop.event_location_id, small: true, stretch: true = location_select workshop.event_location_id, small: true
= block_select workshop.block.present? ? "#{workshop.block['day']}:#{workshop.block['block']}" : nil, small: true = block_select workshop.block.present? ? "#{workshop.block['day']}:#{workshop.block['block']}" : nil, small: true
.actions.next-prev .actions.next-prev
= button_tag :deschedule, value: :deschedule_workshop, class: [:delete, 'booked-only'] = button_tag :deschedule, value: :deschedule_workshop, class: [:delete, 'booked-only', :small]
= button_tag :reschedule, value: :schedule_workshop, class: [:secondary, 'booked-only'] = button_tag :reschedule, value: :schedule_workshop, class: [:secondary, 'booked-only', :small]
= button_tag :schedule_workshop, value: :schedule_workshop, class: 'not-booked-only' = button_tag :schedule_workshop, value: :schedule_workshop, class: ['not-booked-only', :small]

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

@ -1,5 +1,17 @@
.details .details
= data_set(:h4, 'articles.admin.stats.headings.registrations') do = data_set(:h4, 'articles.admin.stats.headings.registrations') do
= @registrations.size = @registrations.size
= data_set(:h4, 'articles.admin.stats.headings.bikes') do
= "#{@bikes} (#{(@bikes / @registration_count) * 100.0}%)"
= data_set(:h4, 'articles.admin.stats.headings.food.meat') do
= "#{@food[:meat]} (#{(@food[:meat] / @food[:all]) * 100.0}%)"
= data_set(:h4, 'articles.admin.stats.headings.food.vegetarian') do
= "#{@food[:vegetarian]} (#{(@food[:vegetarian] / @food[:all]) * 100.0}%)"
= data_set(:h4, 'articles.admin.stats.headings.food.vegan') do
= "#{@food[:vegan]} (#{(@food[:vegan] / @food[:all]) * 100.0}%)"
= data_set(:h4, 'articles.admin.stats.headings.donation_count') do
= "#{@donation_count} (#{(@donation_count / @registration_count) * 100.0}%)"
= data_set(:h4, 'articles.admin.stats.headings.donation_total') do
= "$#{@donations}"
.actions .actions
= link_to (_'links.download.Excel'), administration_step_path(@this_conference.slug, :stats, :format => :xlsx), class: [:button, :download] = link_to (_'links.download.Excel'), administration_step_path(@this_conference.slug, :stats, :format => :xlsx), class: [:button, :download]

6
app/views/layouts/application.html.haml

@ -74,5 +74,11 @@
= link_to (_'forms.actions.generic.facebook_sign_in','Facebook Sign In'), auth_at_provider_path(provider: :facebook, dest: settings_path), class: [:button, :facebook] = link_to (_'forms.actions.generic.facebook_sign_in','Facebook Sign In'), auth_at_provider_path(provider: :facebook, dest: settings_path), class: [:button, :facebook]
%button.close.subdued=_'forms.actions.generic.cancel' %button.close.subdued=_'forms.actions.generic.cancel'
- if @event_dlg.present?
.event-dlg#event-dlg{ data: { type: :event } }
.event-details
.actions.right
%a.more-details.button{href: '#'}=_'articles.workshops.info.read_more'
%button.close-btn.subdued=_'forms.actions.generic.close'
= yield :footer_scripts if content_for?(:footer_scripts) = yield :footer_scripts if content_for?(:footer_scripts)
= inline_scripts = inline_scripts

2
app/views/workshops/_workshop_previews.html.haml

@ -12,4 +12,4 @@
%span.interest-text=interest_text(w) %span.interest-text=interest_text(w)
.workshop-description=richtext w.info, 4 .workshop-description=richtext w.info, 4
.actions.right .actions.right
= link_to (_'articles.workshops.info.read_more'), view_workshop_path(w.conference.slug, w.id), class: 'workshop-link', class: [:button, :small] = link_to (_'articles.workshops.info.read_more'), view_workshop_path(w.conference.slug, w.id), class: ['workshop-link', :button, :small]

2
config/initializers/assets.rb

@ -8,4 +8,4 @@ Rails.application.config.assets.version = '1.0'
# Precompile additional assets. # Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
Rails.application.config.assets.precompile += %w( user-mailer.css map.js pen.js editor.js markdown.js html2canvas.js main.js housing.js favicon.ico ) Rails.application.config.assets.precompile += %w( user-mailer.css map.js pen.js editor.js markdown.js html2canvas.js main.js housing.js schedule.js favicon.ico )

7
config/locales/en.yml

@ -5405,7 +5405,7 @@ en:
notes: Notes notes: Notes
admin: admin:
edit: edit:
info: 'Conference Info' info: Info
companion: Companion companion: Companion
paragraphs: paragraphs:
Policy_Agreement: Ensuring that all attendees feel welcome, safe, and respected at all times is especially important to us all. Please ensure that you have fully read and understand our safer spaces policy below, if you have any questions or concerns you can reach out to the organizers at any time. Policy_Agreement: Ensuring that all attendees feel welcome, safe, and respected at all times is especially important to us all. Please ensure that you have fully read and understand our safer spaces policy below, if you have any questions or concerns you can reach out to the organizers at any time.
@ -5464,6 +5464,9 @@ en:
admin: admin:
edit: edit:
info: This is the copy that is displayed on the front page of the site. info: This is the copy that is displayed on the front page of the site.
schedule:
published: Your scheulde is currently published and viewable on the front-page. Un-publishing the schedule will remove it from the front-page and show a list of proposed workshops instead.
un_published: Your schedule is not yet published. Publishing the schedule will replace the list of proposed workshops on the front-page with the schedule as it is shown below.
companion: Is there someone who you would like us to ensure that you are housed with? 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! arrival_and_departure: If you don't need housing, just tell us how long you plan to hang out with Bike!Bike!
host: host:
@ -5705,6 +5708,8 @@ en:
add_comment: Add Comment add_comment: Add Comment
reply: Reply reply: Reply
add_member: Add add_member: Add
publish: Publish Schedule
un_publish: Un-Publish Schedule
aria: aria:
remove_interest: Click if you are no longer interested in this workshop remove_interest: Click if you are no longer interested in this workshop
show_interest: Click if you are interested in this workshop show_interest: Click if you are interested in this workshop

Loading…
Cancel
Save