Merge pull request #147 from CactusPuppy/master

CS169L Spring 2021 Team 5 Final PR
This commit is contained in:
Michael Ball 2021-05-03 03:18:40 -07:00 committed by GitHub
commit 653395c123
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 684 additions and 94 deletions

View file

@ -55,6 +55,8 @@
//= require bootstrap-select
//= require osem-survey
//= require pagy
//= require fullcalendar-scheduler/main.js
//= require fullcalendar
$(document).ready(function() {
$('a[disabled=disabled]').click(function(event){

View file

@ -0,0 +1,28 @@
$( document ).ready(function() {
let calendarEl = document.getElementById('vert-schedule-full-calendar');
if (!calendarEl) return; //check that we need a vertical schedule
let fullcalData = $('#fullcalendar');
let license_key = "<%= Rails.configuration.fullcalendar[:license_key] %>";
var calendar = new FullCalendar.Calendar(calendarEl, {
schedulerLicenseKey: license_key,
nowIndicator: true,
now: fullcalData.data('now'),
expandRows: true,
allDaySlot: false,
slotMinTime: fullcalData.data('startHour') + ':00:00',
slotMaxTime: fullcalData.data('endHour') + ':00:00',
validRange: {
start: fullcalData.data('startDate'),
end: fullcalData.data('endDate')
},
timeZone: fullcalData.data('timezone'),
initialDate: fullcalData.data('day'),
initialView: 'resourceTimeGridDay',
resources: fullcalData.data('rooms'),
events: fullcalData.data('events')
});
calendar.render();
});

View file

@ -26,4 +26,6 @@
*= require osem-navbar
*= require mastodon
*= require conferences
*= require fullcalendar-scheduler/main.css
*/

View file

@ -40,7 +40,7 @@ class ConferencesController < ApplicationController
@image_url = "#{request.protocol}#{request.host}#{@conference.picture}"
if splashpage.include_cfp
if splashpage.include_cfp?
cfps = @conference.program.cfps
@call_for_events = cfps.find { |call| call.cfp_type == 'events' }
if @call_for_events.try(:open?)
@ -50,31 +50,27 @@ class ConferencesController < ApplicationController
@call_for_tracks = cfps.find { |call| call.cfp_type == 'tracks' }
@call_for_booths = cfps.find { |call| call.cfp_type == 'booths' }
end
if splashpage.include_program
if splashpage.include_program?
@highlights = @conference.highlighted_events.eager_load(:speakers)
if splashpage.include_tracks
if splashpage.include_tracks?
@tracks = @conference.confirmed_tracks.eager_load(
:room
).order('tracks.name')
end
if splashpage.include_booths
if splashpage.include_booths?
@booths = @conference.confirmed_booths.order('title')
end
if splashpage.include_happening_now
events_schedules_list = get_happening_now_events_schedules(@conference)
@events_schedules_limit = EVENTS_PER_PAGE
@events_schedules_length = events_schedules_list.length
@pagy, @events_schedules = pagy_array(events_schedules_list, items: @events_schedules_limit, link_extra: 'data-remote="true"')
@happening_now_url = happening_now_conference_schedule_path(conference_id: @conference.short_title, format: :json)
if splashpage.include_happening_now?
load_happening_now
end
end
if splashpage.include_registrations || splashpage.include_tickets
if splashpage.include_registrations? || splashpage.include_tickets?
@tickets = @conference.tickets.visible.order('price_cents')
end
if splashpage.include_lodgings
if splashpage.include_lodgings?
@lodgings = @conference.lodgings.order('id')
end
if splashpage.include_sponsors
if splashpage.include_sponsors?
@sponsorship_levels = @conference.sponsorship_levels.eager_load(
:sponsors
).order('sponsorship_levels.position ASC', 'sponsors.name')

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true
EVENTS_PER_PAGE = Rails.configuration.conference[:events_per_page]
class ProposalsController < ApplicationController
include ConferenceHelper
before_action :authenticate_user!, except: [:show, :new, :create]
load_resource :conference, find_by: :short_title
load_resource :program, through: :conference, singleton: true
@ -19,6 +22,7 @@ class ProposalsController < ApplicationController
@event_schedule = @event.event_schedules.find_by(schedule_id: @program.selected_schedule_id)
@speakers_ordered = @event.speakers_ordered
@surveys_after_event = @event.surveys.after_event.select(&:active?)
load_happening_now
end
def new

View file

@ -78,6 +78,25 @@ class SchedulesController < ApplicationController
end
end
def vertical_schedule
dates = @conference.start_date..@conference.end_date
# the schedule takes you to today if it is a date of the schedule
current_day = @conference.current_conference_day
@day = current_day.present? ? current_day : dates.first
event_schedules = @program.selected_event_schedules(
includes: [{ event: %i[event_type speakers submitter] }]
)
unless event_schedules
redirect_to events_conference_schedule_path(@conference.short_title)
return
end
@rooms = FullCalendarFormatter.rooms_to_resources(@conference.venue.rooms) if @conference.venue
@event_schedules = FullCalendarFormatter.event_schedules_to_resources(event_schedules)
@now = Time.now.in_time_zone(@conference.timezone).strftime('%FT%T%:z')
end
def app
@qr_code = RQRCode::QRCode.new(conference_schedule_url).as_svg(offset: 20, color: '000', shape_rendering: 'crispEdges', module_size: 11)
end

View file

@ -79,10 +79,42 @@ module ConferenceHelper
end
def get_happening_now_events_schedules(conference)
events_schedules = conference.program.selected_event_schedules(
includes: [:room, { event: %i[track event_type speakers submitter] }]
).select(&:happening_now?)
events_schedules = filter_events_schedules(conference, :happening_now?)
events_schedules ||= []
events_schedules
end
def get_happening_next_events_schedules(conference)
events_schedules = filter_events_schedules(conference, :happening_later?)
if events_schedules.empty?
return []
end
# events_schedules have been sorted by start_time in selected_event_schedules
happening_next_time = events_schedules[0].start_time
events_schedules = events_schedules.select { |s| s.start_time == happening_next_time }
events_schedules
end
def load_happening_now
events_schedules_list = get_happening_now_events_schedules(@conference)
@is_happening_next = false
if events_schedules_list.empty?
events_schedules_list = get_happening_next_events_schedules(@conference)
@is_happening_next = true
end
@events_schedules_limit = EVENTS_PER_PAGE
@events_schedules_length = events_schedules_list.length
@pagy, @events_schedules = pagy_array(events_schedules_list, items: @events_schedules_limit, link_extra: 'data-remote="true"')
end
private
def filter_events_schedules(conference, filter)
conference.program.selected_event_schedules(
includes: [:room, { event: %i[track event_type speakers submitter] }]
).select(&filter)
end
end

View file

@ -31,7 +31,7 @@ class Ability
event.state == 'confirmed'
end
can [:show, :events, :happening_now, :app], Schedule do |schedule|
can [:show, :events, :happening_now, :app, :vertical_schedule], Schedule do |schedule|
schedule.program.schedule_public
end

View file

@ -70,6 +70,14 @@ class EventSchedule < ApplicationRecord
event_time_range.overlaps?(now_range)
end
def happening_later?
# TODO: Save start_time with local timezone info when making an event schedule
in_tz_start = start_time.in_time_zone(timezone)
in_tz_start -= in_tz_start.utc_offset
in_tz_start >= Time.now
end
def self.withdrawn_or_canceled_event_schedules(schedule_ids)
EventSchedule
.unscoped
@ -125,6 +133,14 @@ class EventSchedule < ApplicationRecord
other.schedule_id == schedule_id
end
def start_time_in_conference_timezone
time_in_conference_timezone(start_time)
end
def end_time_in_conference_timezone
time_in_conference_timezone(end_time)
end
private
def replaced_event_schedules
@ -179,4 +195,10 @@ class EventSchedule < ApplicationRecord
errors.add(:schedule, "must be one of #{event.track.name} track's schedules") unless event.track.schedules.include?(schedule)
end
def time_in_conference_timezone(time)
time_in_tz = time.in_time_zone(timezone)
time_in_tz -= time_in_tz.utc_offset
time_in_tz
end
end

View file

@ -0,0 +1,42 @@
class FullCalendarFormatter
def self.rooms_to_resources(rooms)
rooms.map { |room| room_to_resource(room) }.to_json
end
def self.event_schedules_to_resources(event_schedules)
return '[]' if event_schedules.empty?
conference = event_schedules.first.schedule.program.conference
event_schedules.map { |event_schedule| event_schedule_to_resource(conference, event_schedule) }.to_json
end
class << self
include FormatHelper
private
def room_to_resource(room)
{
id: room.guid,
title: room.name
}
end
def event_schedule_to_resource(conference, event_schedule)
event_type_color = event_schedule.event.event_type.color
url = Rails.application.routes.url_helpers.conference_program_proposal_path(conference.short_title, event_schedule.event.id)
{
id: event_schedule.event.guid,
title: event_schedule.event.title,
start: event_schedule.start_time_in_conference_timezone,
end: event_schedule.end_time_in_conference_timezone,
resourceId: event_schedule.room.guid,
url: url,
borderColor: event_type_color,
backgroundColor: event_type_color,
textColor: contrast_color(event_type_color)
}
end
end
end

View file

@ -1,7 +1,7 @@
.row
.col-md-12
.page-header
%h1 Session Materials
%h1 #{@conference.title} Materials
%p.text-muted
Conference materials will be displayed on the events in the
= link_to 'schedule,', conference_schedule_path(@conference.short_title)

View file

@ -57,7 +57,7 @@
- if @conference.program.schedule_public
%td {schedule_link}
%td The link to complete schedule of the conference
- if @conference.splashpage && @conference.splashpage.public
- if @conference.splashpage && @conference.splashpage.public?
%tr
%td {conference_splash_link}
%td The link to conference splash page

View file

@ -49,7 +49,7 @@
%i{ class: "fa-li #{icon_for_todo @splashpage.include_social_media?}" }
Display social media links
%li
- if @conference.splashpage && @conference.splashpage.public
- if @conference.splashpage && @conference.splashpage.public?
%i{ class: "fa-li #{icon_for_todo @splashpage.public?}" }
%text-muted.publicorprivate Public
- else

View file

@ -3,7 +3,8 @@
= render 'happening_now', conference: conference,
events_schedules: events_schedules, pagy: pagy,
events_schedules_length: events_schedules_length,
events_schedules_limit: events_schedules_limit
events_schedules_limit: events_schedules_limit,
is_happening_next: is_happening_next
= content_for :about do
#about
@ -14,9 +15,9 @@
.container
.row
-# happening now events are displayed second in md or lg view
- if conference.splashpage.include_happening_now && conference.splashpage.include_program
- if conference.splashpage.include_happening_now? && conference.splashpage.include_program?
- if conference.description.present?
.col-md-6.col-md-push-6.col-lg-4.col-lg-push-8
.col-md-6.col-md-push-6.col-lg-4.col-lg-push-8{ style: 'margin-top: 60px' }
= yield :happening_now
- else
.col-md-12

View file

@ -1,12 +1,15 @@
- if conference.splashpage.include_program && conference.splashpage.include_happening_now
- if events_schedules.any?
.row
%h2.text-center{ style: 'margin-bottom:30px' } Happening Now
- events_schedules.each do |event_schedule|
= render 'schedules/event', conference: conference, event_schedule: event_schedule, event: event_schedule.event, is_brief: true
- if events_schedules_length > events_schedules_limit
.container{ style: 'width:100%; text-align:center' }
!= pagy_bootstrap_nav_js(pagy)
- else
.row
%h3.text-center There are no events happening now.
- if events_schedules.present? && events_schedules.any?
.row
%h3.text-left{ style: 'margin-bottom:30px; padding-left:20px' }
- if is_happening_next
Events Happening Next
- else
Events Happening Now
- events_schedules.each do |event_schedule|
= render 'schedules/event', conference: conference, event_schedule: event_schedule, event: event_schedule.event, is_brief: true
- if events_schedules_length > events_schedules_limit
.container{ style: 'width:100%; text-align:center' }
!= pagy_bootstrap_nav_js(pagy)
- else
.row
%h3.text-center There are no events scheduled yet.

View file

@ -1,6 +1,11 @@
- cache [conference, venue, '#splash#header'] do
#banner{ style: ("background-image: url(#{conference.picture_url})" if conference.picture_url) }
.container
- if user_signed_in?
- if current_user.ticket_purchases.by_conference(@conference).empty?
.alert.bg-info{ :role => "alert", :style => "margin-bottom: 100px" }
You have not purchased any tickets for this conference yet.
= link_to "Book your tickets now!", "#tickets"
.row
.col-md-6.col-md-offset-3{ id: (conference.picture? ? "header-image" : "header-no-image") }
.row

View file

@ -49,21 +49,22 @@
= render 'about_and_happening_now', conference: @conference,
events_schedules: @events_schedules, pagy: @pagy,
events_schedules_length: @events_schedules_length,
events_schedules_limit: @events_schedules_limit
events_schedules_limit: @events_schedules_limit,
is_happening_next: @is_happening_next
-# calls for content, or program
- if @conference.splashpage.include_cfp
- if @conference.splashpage.include_cfp?
= render 'call_for_content', conference: @conference,
call_for_events: @call_for_events, call_for_tracks: @call_for_tracks,
call_for_booths: @call_for_booths,
event_types: @event_types, tracks: @track_names
- if @conference.splashpage.include_program
- if @conference.splashpage.include_program?
= render 'program', conference: @conference, tracks: @tracks,
highlights: @highlights, booths: @booths
-# attendance/registration
- if @conference.splashpage.include_registrations
- if @conference.splashpage.include_registrations?
- if @conference.registration_open?
= render 'registration', conference: @conference,
registration_period: @conference.registration_period,
@ -72,20 +73,20 @@
= render 'tickets', conference: @conference, tickets: @tickets
-# geo
- if @conference.splashpage.include_venue && @conference.venue
- if @conference.splashpage.include_venue? && @conference.venue
= render 'venue', conference: @conference, venue: @conference.venue,
commercial: @conference.venue.commercial
- if @conference.splashpage.include_lodgings && @conference.lodgings.any?
= render 'lodging', venue: @conference.venue, lodgings: @lodgings
-# sponsorship
- if @conference.splashpage.include_sponsors
- if @conference.splashpage.include_sponsors?
= render 'sponsors', conference: @conference,
sponsorship_levels: @sponsorship_levels,
sponsors: @sponsors
-# footer
- if @conference.splashpage.include_social_media
- if @conference.splashpage.include_social_media?
- if @conference.contact.has_social_media?
= render 'social_media', contact: @conference.contact
= render 'footer'

View file

@ -1,5 +1,6 @@
$('#happening-now').html("<%= j(render 'happening_now', conference: @conference,
events_schedules: @events_schedules, pagy: @pagy,
events_schedules_length: @events_schedules_length,
events_schedules_limit: @events_schedules_limit)%>");
events_schedules_limit: @events_schedules_limit,
is_happening_next: @is_happening_next) %>");
Pagy.init(document.getElementById('happening-now'));

View file

@ -25,9 +25,10 @@
.col-md-4
%p{style: "margin-top: 20px"}
- if @event_schedule&.start_time
= link_to google_calendar_link(@event_schedule), target: '_blank', class: 'btn btn-success btn-mini' do
%i.fa.fa-calendar
Add to Google Calendar (beta)
- if user_signed_in?
= link_to google_calendar_link(@event_schedule), target: '_blank', class: 'btn btn-success btn-mini' do
%i.fa.fa-calendar
Add to Google Calendar (beta)
- if can?(:update, @event) && @event.require_registration?
= link_to 'Registrations', registrations_conference_program_proposal_path(@conference.short_title, @event), class: 'btn btn-mini btn-success'
- if can?(:edit, @event)
@ -51,7 +52,7 @@
- @event.volunteers.each do |volunteer|
= render 'volunteer_info', speaker: volunteer, show_bio: false
.col-md-9
.col-md-6
.row
.col-md-12
.lead
@ -138,6 +139,13 @@
- if @surveys_after_event.any? && @event.ended?
.page-header
= render partial: 'surveys/list', locals: { surveys: @surveys_after_event, conference: @conference }
.col-md-3
#happening-now
= render 'conferences/happening_now', conference: @conference,
events_schedules: @events_schedules, pagy: @pagy,
events_schedules_length: @events_schedules_length,
events_schedules_limit: @events_schedules_limit,
is_happening_next: @is_happening_next
- if @event.committee_review.present? || @event.submission_text.present? && can?(:edit, @event)
%hr

View file

@ -0,0 +1,6 @@
$('#happening-now').html("<%= j(render 'conferences/happening_now', conference: @conference,
events_schedules: @events_schedules, pagy: @pagy,
events_schedules_length: @events_schedules_length,
events_schedules_limit: @events_schedules_limit,
is_happening_next: @is_happening_next) %>");
Pagy.init(document.getElementById('happening-now'));

View file

@ -0,0 +1,12 @@
.container#program
= render 'schedule_tabs', active: 'vertical_schedule'
%h1.text-center
Vertical Schedule for
= @conference.title
#vert-schedule-full-calendar
#fullcalendar{ data: { rooms: @rooms, events: @event_schedules, day: @day,
'start-hour': @conference.start_hour, 'end-hour': @conference.end_hour,
'start-date': @conference.start_date, 'end-date': @conference.end_date + 1.day,
'timezone': @conference.timezone, 'now': @now } }