Commit b7bac51a authored by Zac Wood's avatar Zac Wood
Browse files

Export working

parent a786e4ad
...@@ -18,3 +18,10 @@ ...@@ -18,3 +18,10 @@
#share-header { #share-header {
margin-top: 16px; margin-top: 16px;
} }
.btn-variant{
background-color: transparent;
text-align: left;
border: none;
padding: 0px;
}
...@@ -8,7 +8,7 @@ class API::SchedulesController < ApplicationController ...@@ -8,7 +8,7 @@ class API::SchedulesController < ApplicationController
param :crns, String, desc: 'Comma separated list of crns to include as events in the calendar', required: true param :crns, String, desc: 'Comma separated list of crns to include as events in the calendar', required: true
def index def index
crns = params["crns"].split ',' crns = params["crns"].split ','
@schedule = Schedule.new crns @schedule = Schedule.new(crns, @semester.season)
render plain: @schedule.to_ical # render a plaintext iCal file render plain: @schedule.to_ical # render a plaintext iCal file
end end
end end
...@@ -25,9 +25,11 @@ class SchedulesController < ApplicationController ...@@ -25,9 +25,11 @@ class SchedulesController < ApplicationController
} }
@events = generate_fullcalender_events(@without_online) @events = generate_fullcalender_events(@without_online)
sections = @cart.map do |s| sections = @cart.map do |s|
s.serializable_hash.merge(instructor_name: s.instructor.name, instructor_url: instructor_url(s.instructor)) s.serializable_hash.merge(instructor_name: s.instructor.name, instructor_url: instructor_url(s.instructor))
end end
render json: { events: @events, sections: sections } render json: { events: @events, sections: sections }
end end
end end
...@@ -3,7 +3,6 @@ import BigCalendar from 'react-big-calendar'; ...@@ -3,7 +3,6 @@ import BigCalendar from 'react-big-calendar';
import Toolbar from 'src/Toolbar'; import Toolbar from 'src/Toolbar';
import moment from 'moment'; import moment from 'moment';
import '!style-loader!css-loader!react-big-calendar/lib/css/react-big-calendar.css'; import '!style-loader!css-loader!react-big-calendar/lib/css/react-big-calendar.css';
import withSizes from 'react-sizes';
const localizer = BigCalendar.momentLocalizer(moment); const localizer = BigCalendar.momentLocalizer(moment);
......
...@@ -2,6 +2,7 @@ import React from 'react'; ...@@ -2,6 +2,7 @@ import React from 'react';
import Calendar from 'src/Calendar'; import Calendar from 'src/Calendar';
import Cart from 'src/Cart'; import Cart from 'src/Cart';
import SectionList from 'src/SectionList'; import SectionList from 'src/SectionList';
import ExportModal from 'src/ExportModal';
import QuickAdd from 'src/QuickAdd'; import QuickAdd from 'src/QuickAdd';
import moment from 'moment'; import moment from 'moment';
...@@ -36,8 +37,28 @@ export default class CalendarPage extends React.Component { ...@@ -36,8 +37,28 @@ export default class CalendarPage extends React.Component {
render() { render() {
return ( return (
<div> <div className="container">
<Calendar events={this.events()} /> <Calendar events={this.events()} />
<div className="container mt-4">
<div className="row justify-content-around">
<div className="col-4">
<div className="d-flex justify-content-center">
<button className="btn btn-lg btn-primary" data-toggle="modal" data-target="#exportModal">
<i className="fas fa-download mr-2" />
Export Schedule
</button>
</div>
</div>
<div className="col-4">
<div className="d-flex justify-content-center">
<button className="btn btn-lg btn-secondary">
<i className="fas fa-share-square mr-2" />
Share
</button>
</div>
</div>
</div>
</div>
{this.state.sections.length > 0 ? ( {this.state.sections.length > 0 ? (
<div className="d-flex justify-content-between align-items-end"> <div className="d-flex justify-content-between align-items-end">
<h2 className="mt-4">Your Schedule</h2>{' '} <h2 className="mt-4">Your Schedule</h2>{' '}
...@@ -48,6 +69,7 @@ export default class CalendarPage extends React.Component { ...@@ -48,6 +69,7 @@ export default class CalendarPage extends React.Component {
) : null} ) : null}
<SectionList onClick={this.toggleSection} sections={this.state.sections} expanded={true} /> <SectionList onClick={this.toggleSection} sections={this.state.sections} expanded={true} />
<QuickAdd loadCalendar={this.loadEvents} /> <QuickAdd loadCalendar={this.loadEvents} />
<ExportModal />
</div> </div>
); );
} }
......
...@@ -11,7 +11,7 @@ export default class Section extends React.Component { ...@@ -11,7 +11,7 @@ export default class Section extends React.Component {
onClick = e => { onClick = e => {
e.stopPropagation(); e.stopPropagation();
console.log(e.target.tagName); console.log(e.target.tagName);
if (e.target.tagName === 'A') return; if (e.target.tagName === 'A') return; // if we clicked on a link, don't add the section to the cart
Cart.toggleCrn(this.props.crn); Cart.toggleCrn(this.props.crn);
this.setState({ inCart: Cart.includesCrn(this.props.crn) }); this.setState({ inCart: Cart.includesCrn(this.props.crn) });
...@@ -20,7 +20,7 @@ export default class Section extends React.Component { ...@@ -20,7 +20,7 @@ export default class Section extends React.Component {
}; };
render() { render() {
const { name, title, crn, instructor_name, instructor_url, teaching_rating, course_rating, location, days, start_time, end_time } = this.props; const { name, title, crn, instructor_name, instructor_url, teaching_rating, location, days, start_time, end_time } = this.props;
const { inCart } = this.state; const { inCart } = this.state;
const percent = teaching_rating ? <Stars percent={(teaching_rating[0] / 5) * 100} /> : null; const percent = teaching_rating ? <Stars percent={(teaching_rating[0] / 5) * 100} /> : null;
...@@ -51,7 +51,14 @@ export default class Section extends React.Component { ...@@ -51,7 +51,14 @@ export default class Section extends React.Component {
</p> </p>
{remove} {remove}
{add} {add}
<i className="fas fa-chalkboard-teacher" /> <a href={instructor_url}>{instructor_name}</a> {percent} <i className="fas fa-chalkboard-teacher" />{' '}
{instructor_name !== 'TBA' ? (
<span>
<a href={instructor_url}>{instructor_name}</a> {percent}
</span>
) : (
<span>{instructor_name}</span>
)}
<br /> <br />
<i className="fas fa-map-marker-alt" /> {location} <br /> <i className="fas fa-map-marker-alt" /> {location} <br />
<i className="fas fa-clock" /> {days}, {start_time} - {end_time} <br /> <i className="fas fa-clock" /> {days}, {start_time} - {end_time} <br />
......
...@@ -13,14 +13,16 @@ class CustomToolbar extends Toolbar { ...@@ -13,14 +13,16 @@ class CustomToolbar extends Toolbar {
return ( return (
<div className="rbc-toolbar d-flex justify-content-between"> <div className="rbc-toolbar d-flex justify-content-between">
{!isMobile && ( {!isMobile && (
<span className="rbc-btn-group"> <div>
<button type="button" onClick={() => this.view('day')}> <span className="rbc-btn-group">
Day <button type="button" onClick={() => this.view('day')}>
</button> Day
<button type="button" onClick={() => this.view('week')}> </button>
Week <button type="button" onClick={() => this.view('week')}>
</button> Week
</span> </button>
</span>
</div>
)} )}
<span className="rbc-toolbar-label">{this.props.label}</span> <span className="rbc-toolbar-label">{this.props.label}</span>
......
...@@ -4,9 +4,10 @@ require 'time' ...@@ -4,9 +4,10 @@ require 'time'
# Creates a iCal object given a list of section ids # Creates a iCal object given a list of section ids
class Schedule class Schedule
def initialize(crns) def initialize(crns, season)
@cal = Icalendar::Calendar.new @cal = Icalendar::Calendar.new
@cal.x_wr_calname = 'GMU Schedule' @cal.x_wr_calname = 'GMU Schedule'
@season = season
tzid = "America/New_York" tzid = "America/New_York"
tz = TZInfo::Timezone.get tzid tz = TZInfo::Timezone.get tzid
...@@ -33,10 +34,11 @@ class Schedule ...@@ -33,10 +34,11 @@ class Schedule
@cal.add_event(event) @cal.add_event(event)
end end
# if section.days.start_with? "M" # Add the columbus day make up for Fall
# col_day_makeup = generate_event_after_columbus_day(section) if @season == "Fall" && section.days.start_with?("M")
# @cal.add_event(col_day_makeup) col_day_makeup = generate_event_after_columbus_day(section)
# end @cal.add_event(col_day_makeup)
end
end end
end end
...@@ -101,7 +103,16 @@ class Schedule ...@@ -101,7 +103,16 @@ class Schedule
# Every section's start_date is the first Monday of the semester. # Every section's start_date is the first Monday of the semester.
# So we need to add an exclusion for that day unless the class is held on Mondays # So we need to add an exclusion for that day unless the class is held on Mondays
unless section.days.start_with? "T" start_day = case @season
when "Fall"
"M"
when "Spring"
"T"
when "Summer"
"M"
end
unless section.days.start_with? start_day
exdates << generate_exdate( exdates << generate_exdate(
section.start_date.to_formatted_s(:number), section.start_date.to_formatted_s(:number),
section.start_time section.start_time
...@@ -109,12 +120,12 @@ class Schedule ...@@ -109,12 +120,12 @@ class Schedule
end end
# If the section meets on Tuesdays, add an exdate for the day after columbus day # If the section meets on Tuesdays, add an exdate for the day after columbus day
# if section.days.start_with? "T" if @season == "Fall" && section.days.start_with?("T")
# exdates << generate_exdate( exdates << generate_exdate(
# Date.new(2018, 10, 9).to_formatted_s(:number), Date.new(2019, 10, 15).to_formatted_s(:number),
# section.start_time section.start_time
# ) )
# end end
exdates exdates
end end
...@@ -138,7 +149,7 @@ class Schedule ...@@ -138,7 +149,7 @@ class Schedule
event.description = section.title + " (Columbus Day makeup)" event.description = section.title + " (Columbus Day makeup)"
event.location = section.location event.location = section.location
after_columbus_day = Date.new 2018, 10, 9 after_columbus_day = Date.new(2019, 10, 15)
event.dtstart = Icalendar::Values::DateTime.new(formatted_datetime_str(after_columbus_day, section.start_time)) event.dtstart = Icalendar::Values::DateTime.new(formatted_datetime_str(after_columbus_day, section.start_time))
event.dtend = Icalendar::Values::DateTime.new(formatted_datetime_str(after_columbus_day, section.end_time)) event.dtend = Icalendar::Values::DateTime.new(formatted_datetime_str(after_columbus_day, section.end_time))
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<div class="col-lg-8 col-12"> <div class="col-lg-8 col-12">
<% @semesters.each do |semester, sections| %> <% @semesters.each do |semester, sections| %>
<h2><%= semester %></h2> <h2><%= semester %></h2>
<%= render(partial: 'shared/section', collection: sections) %> <%= render(partial: 'shared/section', collection: sections, locals: { show_instr: false }) %>
<br/> <br/>
<% end %> <% end %>
</div> </div>
......
<%= javascript_pack_tag 'schedules' %> <%= javascript_pack_tag 'schedules' %>
<%= stylesheet_link_tag 'schedules' %> <%= stylesheet_link_tag 'schedules' %>
<div id="root"></div> <div id="root"></div>
<!-- Export Modal -->
<div class="modal fade" id="exportModal" tabindex="-1" role="dialog" aria-labelledby="exportModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exportModalLabel">Your calendar has been generated!</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h5>Apple Calendar</h5>
To add your schedule to Apple Calendar, click the "Add to calendar" button below. If you are on a device
running macOS or iOS, this will open a dialogue which will walk you through adding the calendar.
<hr />
<h5>Google Calendar</h5>
<strong>On desktop:</strong>
<br />
First, download the calendar file using the "Download calendar file" below. Open your <a href="https://calendar.google.com/" target="_blank">Google Calendar</a>. Click the "Settings" button in the top
right, and then click the Settings tab. In the menu on the left, click "Import & export" and "Import". Now, upload the calendar file you downloaded and click "Import".
<br />
<strong>On mobile (Android only):</strong>
<br />
Click the "Download calendar file" button. This will download the calendar file which you may then open and
add to your calendar.
<hr />
<h5>Outlook Calendar</h5>
<strong>On desktop (Windows):</strong>
<br>
First, download the calendar file using the “Download calendar file” button below. In Outlook, choose File, then Open and Export, and then Import/Export. In the Import and Export Wizard Box, choose “Import and iCalendar (.ics) or vCalendar file (.vcs)” and the “next” button. Search for the button you downloaded in the beginning. Click “Okay” and then “Import.”
<br>
<strong>On desktop (Mac):</strong>
First, download the calendar file using the “Download calendar file” button below. Open Outlook and make sure the calendar in which you want to import the file into has a checkmark next to it. Alternatively, you can add it into a new calendar by clicking the “Organize” tab and then the “New Calendar” button. Double click the new Calendar to rename it. Open the Finder application and search for the file you downloaded in the beginning. Then, drag and drop the file into the desired Calendar area.
<br>
<strong>Outlook Online (Classic Layout)</strong>
To check if you are using the Classic Layout, look in the top right and see if “The new Outlook” bar is slid to the left. If it is not, you may consider reading “The New Outlook Layout” instructions or clicking the bar to slide it to the left. First, download the calendar file using the “Download calendar file” button below. Login onto your <a href=https://outlook.live.com/owa/ target="blank">Outlook</a> and click the calendar icon on the bottom left. On the menu bar, located above the Calendar, choose the “Add Calendar” menu. From the drop down menu, click import from file and browse for the calendar file you downloaded in the beginning. Click the save icon, then the calendar will be imported.
<br>
<strong>Outlook Online (New Outlook Layout)</strong>
To check if you are using the New Outlook Layout, look in the top right and see if “The new Outlook” bar is slid to the right. If it is not, you may consider reading the “Classic Layout” instructions or clicking the bar to slide it to the right. First download the calendar file using the “Download calendar file” button below. Login onto your <a href=https://outlook.live.com/owa/ target="blank">Outlook</a> and click the calendar icon on the bottom left. On the left side bar, under “Calendars”, click the “Discover calendars” button. Choose on the “From File” menu under the “Import” Section. Then click the browse button and search for the file you downloaded in the beginning. Lastly, choose “Import” and your calendar will be displayed.
<h5>.ics file</h5>
To download a .ics file containing your schedule, click the "Download calendar file" button below.
</div>
<div class="modal-footer flex">
<button id="download-ics" type="button" class="btn btn-secondary">Download calendar file</button>
<button id="add-to-system" type="button" class="btn btn-primary">Add to system calendar</button>
</div>
</div>
</div>
</div>
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
<% editable = true %> <% editable = true %>
<% end %> <% end %>
<% unless defined?(show_instr) %>
<% show_instr = true %>
<% end %>
<li id="section-<%= section.id %>" <li id="section-<%= section.id %>"
class="list-group-item section-item" class="list-group-item section-item"
data-crn="<%= section.crn %>" data-crn="<%= section.crn %>"
...@@ -14,17 +18,20 @@ ...@@ -14,17 +18,20 @@
<% if editable %> <% if editable %>
<span class="float-right text-center add-remove-btn"><i id="icon" class="fas fa-ellipsis-h"></i><br/><span class="text">Add</span></span> <span class="float-right text-center add-remove-btn"><i id="icon" class="fas fa-ellipsis-h"></i><br/><span class="text">Add</span></span>
<% end %> <% end %>
<i class="fas fa-chalkboard-teacher"></i> <i class="fas fa-chalkboard-teacher"></i>
<% if section.instructor.name == "TBA" %> <% if section.instructor.name == "TBA" %>
TBA TBA
<% else %> <% else %>
<%= link_to section.instructor.name, section.instructor %> <%= link_to section.instructor.name, section.instructor %>
<% unless section.instructor.rating.nil? %> <% unless section.instructor.rating.nil? || !show_instr %>
<%= render partial: 'shared/stars', locals: { percent: (section.instructor.rating[0] / 5 * 100).to_i }%> <%= render partial: 'shared/stars', locals: { percent: (section.instructor.rating[0] / 5 * 100).to_i }%>
<% end %> <% end %>
<% end %> <% end %>
<br/> <br/>
<i class="fas fa-map-marker-alt"></i> <%= section.location %> <br/> <i class="fas fa-map-marker-alt"></i> <%= section.location %> <br/>
<i class="fas fa-clock"></i> <%= "#{section.days}, #{section.start_time}-#{section.end_time}" %> <br/> <i class="fas fa-clock"></i> <%= "#{section.days}, #{section.start_time}-#{section.end_time}" %> <br/>
......
"Spring 2019":
- "2019-3-11"
- "2019-3-12"
- "2019-3-13"
- "2019-3-14"
- "2019-3-15"
- "2019-3-16"
- "2019-3-17"
"Fall 2019":
- "2019-10-14"
- "2019-11-27"
- "2019-11-28"
- "2019-11-29"
...@@ -98,16 +98,15 @@ def wipe_db ...@@ -98,16 +98,15 @@ def wipe_db
end end
def load_closures def load_closures
# create closures for the days there will be no classes semesters = YAML.load_file("db/closures.yaml")
# see: https://registrar.gmu.edu/calendars/fall-2018/ semesters.each do |semester, dates|
# fall2018 = Semester.find_by(season: 'Fall', year: '2018') season, year = semester.split
# Closure.create! date: Date.new(2018, 9, 3), semester: fall2018 s = Semester.find_by(season: season, year: year)
# Closure.create! date: Date.new(2018, 10, 8), semester: fall2018 next if s.nil?
# (21..25).each { |n| Closure.create! date: Date.new(2018, 11, n), semester: fall2018 } dates.each do |date|
# (10..19).each { |n| Closure.create! date: Date.new(2018, 12, n), semester: fall2018 } Closure.create!(date: Date.strptime(date, "%Y-%m-%d"), semester: s)
spring2019 = Semester.find_by(season: 'Spring', year: '2019') end
return if spring2019.nil? end
(11..17).each { |day| Closure.find_or_create_by! date: Date.new(2019, 3, day), semester: spring2019 }
end end
def main def main
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment