Commit 84a72fab authored by Zac Wood's avatar Zac Wood

Merge branch 'cleanup' into dev-v2

parents 9b0290a3 9d104142
......@@ -24,7 +24,7 @@ const elementFromString = string => {
};
document.addEventListener('DOMContentLoaded', () => {
this.schedule = new Schedule();
this.cart = new Cart();
});
const setSemester = async select => {
......
class Schedule {
class Cart {
constructor() {
this.isOpen = false;
this._courses = {}; // {title, id, sections: {id, crn}}
......@@ -12,7 +12,7 @@ class Schedule {
}
document.getElementById('course-counter').innerText = Object.keys(this._courses).length;
this._ids = Array.from(document.getElementById('schedule').children).map(e => e.dataset.crn);
this._ids = Array.from(document.getElementById('cart-courses').children).map(e => e.dataset.crn);
}
get crns() {
......@@ -45,12 +45,12 @@ class Schedule {
addCourse(course) {
this._courses[course.id] = course;
const parent = document.querySelector('#schedule');
const current = parent.querySelector(`#schedule-${course.id}`);
const courseList = document.getElementById('cart-courses');
const courseNode = courseList.querySelector(`#schedule-${course.id}`);
const newNode = this._constructCourseNode(course);
if (current !== null) parent.replaceChild(newNode, current);
else parent.appendChild(newNode);
if (courseNode !== null) courseList.replaceChild(newNode, courseNode);
else courseList.appendChild(newNode);
document.getElementById('course-counter').innerText = Object.keys(this._courses).length;
fetch(`/sessions/update?section_ids=${this.ids.join(',')}`, { cache: 'no-store' });
......@@ -65,9 +65,9 @@ class Schedule {
delete this._courses[id];
const parent = document.querySelector('#schedule');
const current = parent.querySelector(`#schedule-${id}`);
parent.removeChild(current);
const courseList = document.getElementById('cart-courses');
const current = courseList.querySelector(`#schedule-${id}`);
courseList.removeChild(current);
document.getElementById('course-counter').innerText = Object.keys(this._courses).length;
fetch(`/sessions/update?section_ids=${this.ids.join(',')}`, { cache: 'no-store' });
......@@ -93,7 +93,7 @@ class Schedule {
if (course) {
course.sections.push(section);
const courseNode = document.querySelector('#schedule').querySelector(`#schedule-${course.id}`);
const courseNode = document.getElementById(`#schedule-${course.id}`);
const crnList = courseNode.querySelector('.crns');
crnList.innerText = course.sections.map(s => `#${s.crn}`);
......@@ -109,7 +109,7 @@ class Schedule {
removeSection(section) {
const course = this.courseContainingSection(section.id);
course.sections = course.sections.filter(s => s.id !== section.id);
const schedule = document.querySelector('#schedule');
const schedule = document.querySelector('#cart-courses');
const courseNode = schedule.querySelector(`#schedule-${course.id}`);
const crnList = courseNode.querySelector('.crns');
if (course.sections.length === 0) {
......@@ -148,5 +148,5 @@ class Schedule {
}
const removeCourse = id => {
this.schedule.removeCourse(id);
this.cart.removeCourse(id);
};
document.addEventListener('DOMContentLoaded', () => {
const eventsTemplate = document.querySelector('#events');
if (eventsTemplate) {
const eventsJSON = eventsTemplate.dataset.events;
const events = JSON.parse(eventsJSON);
console.log(events);
$('#calendar').fullCalendar({
defaultDate: new Date(2019, 0, 14),
defaultView: 'agendaWeek',
header: false,
events: events,
});
}
});
......@@ -9,23 +9,23 @@ const addCourse = (event, id) => {
const sectionsItems = Array.from(courseCard.querySelectorAll('li'));
const sections = sectionsItems.map(li => ({ ...li.dataset }));
this.schedule.addCourse({ title, id, sections });
this.cart.addCourse({ title, id, sections });
sectionsItems.forEach(s => s.classList.add('selected'));
event.stopPropagation();
};
/**
* Either adds or removes a section from the schedule depending on
* if it is currently in the schedule.
* Either adds or removes a section from the cart depending on
* if it is currently in the cart.
*/
const addOrRemoveFromSchedule = (event, sectionNode) => {
const addOrRemoveFromCart = (event, sectionNode) => {
const section = { ...sectionNode.dataset };
if (this.schedule.includesSection(section.id)) {
this.schedule.removeSection(section);
if (this.cart.includesSection(section.id)) {
this.cart.removeSection(section);
sectionNode.classList.remove('selected');
} else {
this.schedule.addSection(section);
this.cart.addSection(section);
sectionNode.classList.add('selected');
}
......@@ -33,15 +33,15 @@ const addOrRemoveFromSchedule = (event, sectionNode) => {
};
/**
* Removes a given section from the schedule
* @param {Node} DOM Node of the Section in the schedule
* Removes a given section from the cart
* @param {Node} DOM Node of the Section in the cart
*/
const removeFromSchedule = section => {
const removeFromCart = section => {
const sectionInSearch = sectionWithCrn(section.dataset.crn);
if (sectionInSearch) {
sectionInSearch.classList.remove('selected');
}
this.schedule.removeFromSchedule(section.dataset.crn);
this.cart.removeFromSchedule(section.dataset.crn);
};
/**
......@@ -62,5 +62,5 @@ const toggleSections = course => {
* and sets the link in the modal to it.
*/
const setUrlInModal = () => {
document.getElementById('calendar-link').innerText = `https://${window.location.hostname}/api/schedule?crns=${this.schedule.ids.join(',')}`;
document.getElementById('calendar-link').innerText = `https://${window.location.hostname}/api/schedule?crns=${this.cart.ids.join(',')}`;
};
......@@ -27,23 +27,26 @@ body {
box-shadow: 0 0 5px rgba(0,0,0,0.2);
transition: 0.3s;
.card-header {
display: flex;
flex-direction: column;
display: flex;
flex-direction: column;
}
.card-body {
.attr-list {
display: flex;
flex-direction: row;
justify-content: flex-start;
padding-bottom: 10px;
.attr {
margin-right: 13px;
}
}
.attr-list {
display: flex;
flex-direction: row;
.attr {
.icon {
padding-right: 4px;
}
align-items: center;
display: inline-flex;
white-space: nowrap;
}
}
}
}
......@@ -98,35 +101,8 @@ body {
align-items: center;
}
#navbar {
margin-top: 8px;
margin-bottom: 48px;
}
#logo {
font-size: 24pt;
color: black;
}
.form-control:focus {
border-color: transparent;
box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.075) inset, 0px 0px 0px rgba(0, 0, 255, 0.5);
}
#cart {
display: none;
}
.card .small {
margin-bottom: 16px;
padding: 12px;
}
#add-course-btn:hover {
background-color: rgba(0,0,0,0.2);
}
#calendar {
background-color: white;
padding: 16px;
}
.cart-course {
display: flex; justify-content: space-between;
.title {
min-width: 15%;
}
.crns {
color: gray;
font-size: 10pt;
}
}
#cart {
display: none;
}
// Place all the styles related to the Courses controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
#add-course-btn:hover {
background-color: rgba(0,0,0,0.2);
}
.center-vert {
display: flex;
justify-content: center;
align-items: center;
}
#navbar {
margin-top: 8px;
margin-bottom: 48px;
}
#logo {
font-size: 24pt;
color: black;
}
#calendar {
background-color: white;
padding: 16px;
}
// Place all the styles related to the sessions controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
......@@ -25,11 +25,15 @@ class SchedulesController < ApplicationController
"S": Date.new(2019, 1, 19),
"U": Date.new(2019, 1, 20)
}.freeze
def show
all_sections = @cart.values
# schedules = []
all_sections.each_with_index do |sections, i|
end
@events = @cart.map do |_cid, sections|
s = sections.first
s.days.split('').map do |day|
formatted_date = DAYS[day.to_sym].to_s.tr('-', '')
time = Time.parse(s.start_time).strftime("%H%M%S")
......@@ -41,7 +45,6 @@ class SchedulesController < ApplicationController
end: "#{formatted_date}T#{endtime}"
}
end
end.flatten
end
end
class SearchController < ApplicationController
def index
@results = SearchHelper::GenericItem.fetchall(params[:query], semester: @semester)
results = SearchHelper::GenericItem.fetchall(params[:query], semester: @semester).group_by(&:type)
@instructors = results[:instructor]
@courses = results[:course]
end
end
......@@ -29,9 +29,10 @@ module SearchHelper
end
def self.fetch_instructors(query_data)
Instructor.from_name(Instructor.select("instructors.*, COUNT(course_sections.id) AS section_count"), query_data.search_string)
.left_outer_joins(:course_sections)
.group("instructors.id")
Instructor
.from_name(Instructor.select("instructors.*, COUNT(course_sections.id) AS section_count"), query_data.search_string)
.left_outer_joins(:course_sections)
.group("instructors.id")
end
def self.fetch_courses(query_data)
......
......@@ -13,9 +13,9 @@ class CourseSection < ApplicationRecord
def labs
return nil unless section_type == "Lecture"
lecture_number = name.split[name.split.length-1]
lecture_number = name.split[name.split.length - 1]
course.course_sections.select do |s|
s.title.split[s.title.split.length-1] == lecture_number
s.title.split[s.title.split.length - 1] == lecture_number
end
end
......
......@@ -7,16 +7,6 @@
* var calendar = new Calendar(cal, {
* defaultView: 'agendaWeek'
* }); */
document.addEventListener('DOMContentLoaded', () => {
const eventsJSON = document.querySelector('#events').dataset.events;
const events = JSON.parse(eventsJSON);
console.log(events);
$('#calendar').fullCalendar({
defaultDate: new Date(2019, 0, 14),
defaultView: 'agendaWeek',
header: { right: 'next'},
events: events
});
});
</script>
<% if @results.any? %>
<% @results.each do |result| %>
<% if result.type == :course %>
<%= render partial: 'shared/course', object: result.data %>
<% elsif result.type == :instructor %>
<%= render partial: 'shared/instructor', object: result.data %>
<% unless @instructors.nil? %>
<h2>Instructors</h2>
<div class="row">
<% @instructors.map(&:data).each do |instructor| %>
<div class="col"><%= render partial: 'shared/instructor', object: instructor %></div>
<% end %>
</div>
<hr />
<% end %>
<% unless @courses.nil? %>
<h2>Courses</h2>
<% @courses.map(&:data).each do |course| %>
<div class="col"><%= render partial: 'shared/course', object: course %></div>
<% end %>
<% end %>
<% else %>
<h1>Sorry, we couldn't find anything matching your search.</h1>
<p>Please try again!</p>
<% end %>
<% if @courses.nil? && @instructors.nil? %>
<h1>Sorry, we couldn't find anything matching your search.</h1>
<p>Please try again!</p>
<% end %>
......@@ -4,26 +4,21 @@
<div class="col order-1 order-lg-1" id="cart">
<div class="card">
<div class="card-body">
<h3 class="card-title"><%= link_to 'Your Schedule', schedule_path %></h3>
<h3 class="card-title"><%= link_to 'Your Cart', schedule_path %></h3>
</div>
<ul class="list-group list-group-flush" id="schedule">
<ul class="list-group list-group-flush" id="cart-courses">
<% @cart.each do |cid, sections| %>
<% course = Course.find_by_id(cid) %>
<li id="schedule-<%= cid %>" class="list-group-item schedule-section-card" onclick="removeCourse(<%= cid %>)">
<div style="display: flex; justify-content: space-between;">
<b style="min-width: 15%"><%= "#{course.subject} #{course.course_number}" %></b>
<span class="crns" style="color: gray; font-size: 10pt;">
<li id="schedule-<%= cid %>" class="list-group-item" onclick="removeCourse(<%= cid %>)">
<div class="cart-course">
<b class="title"><%= "#{course.subject} #{course.course_number}" %></b>
<span class="crns">
<%= sections.map { |s| "##{s.crn}" }.join(', ') %>
</span>
</div>
</li>
<% end %>
</ul>
<div class="card-body">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exportModal" onclick="setUrlInModal()">
Export schedule
</button>
</div>
</div>
</div>
......
......@@ -16,9 +16,20 @@
<h5><em><%= course.title %></em></h5>
</div>
<div class="card-body">
<div class="attr-list">
<div class="attr"><i class="fa fa-book"></i> 3 credits</div>
<div class="attr"><i class="fa fa-bars"></i> 3 sections</div>
<div class="attr-list justify-content-start">
<div class="attr">
<div class="icon">
<i class="fa fa-book"></i>
</div>
3 credits
</div>
&nbsp;&nbsp;&nbsp;
<div class="attr">
<div class="icon">
<i class="fa fa-bars"></i>
</div>
3 sections
</div>
</div>
<p class="description"><%= course.description %></p>
......
<div class="card">
<div class="card-header">
<h4><%= "#{instructor.name}" %></h4>
</div>
<div class="card-body">
<div class="attr-list">
<div class="attr"><i class="fa fa-user"></i> Instructor</div>
<div class="attr"><i class="fa fa-bars"></i> <%= "#{instructor.section_count}" %> sections</div>
<div class="card-body">
<div class="attr-list justify-content-between">
<div class="attr">
<div class="icon">
<i class="fa fa-user"></i>
</div>
<%= link_to instructor.name, instructor_path(instructor) %>
</div>
&nbsp;&nbsp;&nbsp;
<div class="attr">
<div class="icon">
<i class="fa fa-bars"></i>
</div>
<%= "#{instructor.section_count}" %> sections
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
</div>
<div class="container-fluid">
<div class="row align-left align-sm-center align-md-right" id="navbar">
<div class="col align-center">
<div>
<div class="center-vert">
<a href="/" id="logo">
<i class="fas fa-calendar-alt"></i>
Schedules
</a>
&nbsp;&nbsp;
<select onchange="setSemester(this)">
<% Semester.all.each do |semester| %>
<option value="<%= semester.id %>" <% if @semester == semester %> selected <% end %> >
<%= "#{semester.season} #{semester.year}" %>
</option>
<% end %>
</select>
</select>
</div>
</div>
<div class="col-sm align-center order-0 order-sm-1" onclick="window.schedule.toggle()">
<div class="col-sm align-center order-0 order-sm-1" onclick="window.cart.toggle()">
<h1 style="margin-top:24px">
<span class="fa-layers fa-fw" id="schedule-icon">
<i class="fas fa-shopping-cart"></i>
......@@ -29,17 +30,15 @@
</span>
</h1>
</div>
<div class="col order-1 order-sm-0">
<form action="/search" class="form">
<div class="form-group">
<div class="input-group" style="width:100%;">
<input name="query" type="text" class="form-control" placeholder="Search by CRN, course, professor..." aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-secondary" type="button">
<i class="fas fa-search"></i>
</button>
</div>
<div class="input-group" style="width:100%;">
<input name="query" type="text" class="form-control" placeholder="Search by CRN, course, professor..." aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-secondary" type="button">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
......@@ -50,6 +49,6 @@
<div class="container-fluid">
<!-- The main screen consists of a row with two columns: the search results, and the cart -->
<div class="row">
<!-- Search result, List of Courses -->
<div class="col-lg-7 col-md-10 mx-auto order-2 order-lg-0" id="search-list">
......@@ -3,7 +3,7 @@
data-crn="<%= section.crn %>"
data-id="<%= section.id %>"
data-cid="<%= course.id %>"
onclick="addOrRemoveFromSchedule(event, this)"
onclick="addOrRemoveFromCart(event, this)"
>
<span style="float:left"><b class="subj"><%= "#{section.name}" %></b>: <%= section.title %></span>
<span style="float:right"><i class="fas fa-map-marker-alt"></i> <%= section.location %></span>
......
......@@ -14,6 +14,7 @@ Rails.application.config.assets.paths << Rails.root.join('node_modules')
Rails.application.config.assets.precompile += %w(
FileSaver.js
schedule.js
cart.js
masonstrap.min.css
masonstrap.min.js
moment.min.js
......
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