Commit 4488f502 authored by Zac Wood's avatar Zac Wood

/schedules page, instructors in search

parent 41b03a55
......@@ -105,7 +105,17 @@ nav {
width: 90%;
}
}
.instructor {
box-shadow: 0 3px 5px -2px $gray;
border-radius: 5px;
padding: 1em 0 0.5em 1em;
margin-bottom: 1em;
border-top: 5px solid $blue;
a {
text-decoration: underline;
}
}
.course {
box-shadow: 0 3px 5px -2px $gray;
border-radius: 5px;
......@@ -133,6 +143,10 @@ nav {
font-family: 'Roboto', sans-serif;
color: $gray;
font-size: 0.9em;
max-height: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.see-more {
......@@ -199,8 +213,9 @@ a {
}
.underline {
text-decoration: underline;
text-decoration: underline !important;
}
.cart {
position: fixed;
right: 5%;
......@@ -241,6 +256,7 @@ footer {
color: white;
background-color: $blue;
width: 1.5em;
height: 1.5em;
text-align: center;
border-radius: 33%;
border-radius: 100%;
}
# Configures the application.
class ApplicationController < ActionController::Base
include BySemester
before_action :set_render_page
def set_render_page
@render_page = true
end
end
class CourseSectionsController < ApplicationController
def index
@render_page = false
crns = params[:crns].split(',')
@sections = crns.map { |crn| CourseSection.latest_by_crn(crn) }
@days = {
"M" => [], "T" => [], "W" => [],
"R" => [], "F" => []
}
@sections.each do |s|
s.days.split('').each do |day|
@days[day] << s unless s.start_time == "TBA"
end
end
@days_map = {
"M" => "Monday", "T" => "Tuesday", "W" => "Wednesday",
"R" => "Thursday", "F" => "Friday"
}
@days.each do |day, sections|
sections.sort! do |a,b|
Time.new(a.start_time) <=> Time.new(b.start_time)
end
end
end
def show
@section = CourseSection.find_by_id(params[:id])
end
......
......@@ -8,8 +8,6 @@ class CoursesController < ApplicationController
.joins(:semester)
.select("semesters.id")
puts semester_ids.map(&:id)
@semesters = Semester.where(id: semester_ids.map(&:id))
@semesters = Semester.sorted_by_date(@semesters)
......
/* eslint no-console:0 */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
......@@ -8,15 +7,19 @@
// layout file, like app/views/layouts/application.html.erb
import 'url-polyfill'
import Turbolinks from 'turbolinks'
Turbolinks.start()
window.addEventListener('DOMContentLoaded', () => {
Turbolinks.start()
setLinks()
window.addEventListener('turbolinks:load', () => {
setInitialLinks()
addListeners()
document.querySelector('#count').innerText = getCart().length
})
function setLinks(crns) {}
function setInitialLinks() {
getCart().forEach(writeLink)
}
function addListeners() {
const links = Array.from(document.querySelectorAll('.add-section'))
......@@ -25,8 +28,7 @@ function addListeners() {
e.preventDefault()
const crn = link.dataset.crn
toggleSection(crn)
console.log(getCart())
writeLinks()
writeLink(crn)
})
}
}
......@@ -41,6 +43,8 @@ function toggleSection(crn) {
} else {
addSection(crn)
}
console.log(getCart())
document.querySelector('#count').innerText = getCart().length
}
function addSection(crn) {
......@@ -53,28 +57,21 @@ function removeSection(crn) {
localStorage.setItem('cart', JSON.stringify(newCart))
}
function writeLinks() {}
function writeLink(crn) {
const item = document.querySelector(`[data-crn="${crn}"]`)
if (!item) return
const icon = item.querySelector('.add-remove-link a i')
const link = item.querySelector('.add-remove-link a span')
if (getCart().includes(crn)) {
link.innerText = ' Remove from cart'
icon.className = 'fas fa-minus'
} else {
link.innerText = ' Add Section to Cart'
icon.className = 'fas fa-plus'
}
}
const elementFromString = string => {
const html = new DOMParser().parseFromString(string, 'text/html')
return html.body.firstChild
}
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function(callback, type, quality) {
var canvas = this
setTimeout(function() {
var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]),
len = binStr.length,
arr = new Uint8Array(len)
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i)
}
callback(new Blob([arr], { type: type || 'image/png' }))
})
},
})
}
const initPage = () => {
if (getCart().length != 0) {
document.getElementById('root').innerHTML = '<i class="fas fa-spinner fa-spin"></i>'
fetch(`/course_sections?crns=${getCart().join(',')}`)
.then(resp => resp.text())
.then(text => {
const tree = elementFromString(text)
const body = tree.querySelector('.page')
document.getElementById('root').innerHTML = body.innerHTML
setInitialLinks()
addListeners()
})
} else {
document.getElementById('root').innerHTML = 'Add classes to your cart to see them here!'
}
document.querySelector('#count').innerText = getCart().length
}
window.addEventListener('DOMContentLoaded', initPage)
function setInitialLinks() {
getCart().forEach(writeLink)
}
function addListeners() {
const links = Array.from(document.querySelectorAll('.add-section'))
for (const link of links) {
link.addEventListener('click', e => {
e.preventDefault()
const crn = link.dataset.crn
toggleSection(crn)
writeLink(crn)
})
}
}
function getCart() {
return JSON.parse(localStorage.getItem('cart') || '[]')
}
function toggleSection(crn) {
if (getCart().includes(crn)) {
removeSection(crn)
} else {
addSection(crn)
}
console.log(getCart())
document.querySelector('#count').innerText = getCart().length
}
function addSection(crn) {
const newCart = [...getCart(), crn]
localStorage.setItem('cart', JSON.stringify(newCart))
}
function removeSection(crn) {
const newCart = getCart().filter(c => c !== crn)
localStorage.setItem('cart', JSON.stringify(newCart))
}
function writeLink(crn) {
const item = document.querySelectorAll(`[data-crn="${crn}"]`)
if (item.length == 0) return
item.forEach(item => {
const icon = item.querySelector('.add-remove-link a i')
const link = item.querySelector('.add-remove-link a span')
if (getCart().includes(crn)) {
link.innerText = ' Remove from cart'
icon.className = 'fas fa-minus'
} else {
link.innerText = ' Add Section to Cart'
icon.className = 'fas fa-plus'
}
})
}
const elementFromString = string => {
const html = new DOMParser().parseFromString(string, 'text/html')
return html.body
}
......@@ -43,7 +43,7 @@ class CourseSection < ApplicationRecord
def self.latest_by_crn(crn)
sems = Semester.sorted_by_date
where(crn: crn).min_by { |s| sems.find_index(s) }
where(crn: crn).min_by { |s| sems.find_index(s.semester) }
end
# Select all course sections that have an instructor that matches the given name
......
<% @days.each do |day, sections| %>
<% next if sections.empty? %>
<h4 style="margin-top: 0.5em"><%= @days_map[day] %></h4>
<ul class="section-list">
<%= render(partial: 'shared/section', collection: sections) %>
</ul>
<% end %>
\ No newline at end of file
......@@ -44,9 +44,15 @@
</head>
<body>
<% if @render_page %>
<%= render 'shared/page' do %>
<%= yield %>
<% end %>
<% else %>
<div class="page">
<%= yield %>
</div>
<% end %>
<!-- Matomo -->
<script type="text/javascript">
......
<%= javascript_pack_tag 'schedules' %>
<%= stylesheet_link_tag 'schedules' %>
<%= render(partial: 'shared/navbar') %>
<h2 style="margin-bottom: 0.5em">Your Schedule</h2>
<div id="root"></div>
<%= javascript_pack_tag('schedules') %>
\ No newline at end of file
<%= render(partial: 'shared/navbar') %>
<div class="search-results">
<% @courses.each do |course| %>
<% (@instructors || []).each do |inst| %>
<section class="instructor">
<h5><a href="/instructors/<%= inst.id %>"> <%= inst.name %></a></h5>
</section>
<% end %>
<% (@courses || []).each do |course| %>
<section class="course">
<h4><a href="/courses/<%= course['id'] %>"><%= course['subject'] %> <%= course['course_number'] %></a></h4>
<h5><em><%= course['title'] %>. <%= course['credits'] %> <%= 'credit'.pluralize(course['credits'].to_i) %>.</em></h5>
......
......@@ -6,10 +6,10 @@
</div>
<%# </div> %>
<div class="cart">
<span id="count">1</span>
<a class="cart" href="/schedule" data-turbolinks="false">
<span id="count">0</span>
<i class="fas fa-shopping-cart"></i>
</div>
</a>
<footer class="footer">
Schedules was built by <a href="https://srct.gmu.edu">Mason SRCT</a> and is completely open source. <br/>
......
......@@ -26,5 +26,10 @@
</div>
<% end %>
<div class="add-remove-link"><i class="fas fa-plus"></i><a data-crn="<%= "#{section.crn}" %>" class="underline add-section">Add Section to Cart</a></div>
<div class="add-remove-link">
<a data-crn="<%= "#{section.crn}" %>" class="underline add-section">
<i class="fas fa-plus add-remove-icon"></i>
<span>Add Section to Cart</span>
</a>
</div>
</li>
......@@ -9,7 +9,7 @@ Rails.application.routes.draw do
get 'sessions/add_bulk'
resources :courses, only: [:show]
resources :course_sections, only: [:show]
resources :course_sections, only: [:index, :show]
resources :instructors, only: [:index, :show]
get 'schedule', to: 'schedules#show', as: 'schedule'
get 'schedule/events', to: 'schedules#events'
......
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