Skip to content

Commit b4e9a23

Browse files
committed
Merge branch 'djacobs-admin-page' into develop
2 parents 90015f2 + 366114f commit b4e9a23

File tree

11 files changed

+296
-103
lines changed

11 files changed

+296
-103
lines changed

app/assets/stylesheets/project4.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ form button:hover, form button:active {
6262
background-color: #7b9095;
6363
}
6464

65+
.dataTables_scrollHeadInner{
66+
padding: 0 !important;
67+
}
68+
6569
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active{
6670
background-color: #b4bfba;
6771
}
@@ -191,6 +195,11 @@ table div, .dataTables_scrollHead, .dataTables_scrollHeadInner, .dataTables_scro
191195
color: green;
192196
}
193197

198+
#upperPanel {
199+
text-align: center;
200+
flex-direction: column;
201+
}
202+
194203
#trash{
195204
font-size: 64px;
196205
}

app/controllers/plans_controller.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ class PlansController < ApplicationController
55
# GET /plans
66
# GET /plans.json
77
def index
8-
@plans = Plan.where(user_id: current_user.id)
8+
if current_user.role == "admin"
9+
@plans = Plan.all
10+
else
11+
@plans = Plan.where(user_id: current_user.id)
12+
end
913
end
1014

1115
# GET /plans/1
1216
# GET /plans/1.json
1317
def show
18+
if @plan.user_id != current_user.id
19+
redirect_to plans_path
20+
end
1421
end
1522

1623
# GET /plans/new

app/javascript/packs/myjs.js

Lines changed: 156 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
var currPlan = false;
2-
var plan = false;
1+
var currPlan = null;
2+
var plan = null;
33
var selectedMajor = "Comp. Sci.";
44
var selectedCatalogYear = 2017;
55
var catalogLoaded = false;
6-
var draggedCourse = false;
7-
var draggedReqOrigin = false;
8-
var draggedPlanOrigin = false;
9-
10-
$(getPlans);
6+
var planTableLoaded = false;
7+
var draggedCourse = null;
8+
var draggedReqOrigin = null;
9+
var draggedPlanOrigin = null;
10+
var draggedCatOrigin = null;
1111

1212
// changes plan, triggered on selection of new plan in dropdown
1313
$(document).on('change', '#planSelect', function (){
@@ -19,15 +19,45 @@ $(document).on('change', '#planSelect', function (){
1919
selectedCatalogYear = parseInt(selected[1]);
2020

2121
// send request to load new plan
22-
getPlans();
22+
getPlan();
2323

2424
});
2525

26-
function getPlans(){
27-
$.get("plans.json", function(plans){
26+
// For loading the table of plans
27+
window.getAllPlans = function(){
28+
$.get("/plans.json", function(plans){
2829
//console.log(plans);
29-
plan = false;
30+
let buttons = [];
31+
let colObjects = [];
32+
for (let p in plans){
33+
let openHtml = "<a href='/plans/" + plans[p].id + "'>Open</a>";
34+
colObjects.push({"plan": plans[p], "open": openHtml });
35+
}
36+
if (!planTableLoaded){
37+
$("#plansTable").DataTable( {
38+
"dom": '<"top"if>t',
39+
"data": colObjects,
40+
"columns": [
41+
{ "data": "plan.user.login" },
42+
{ "data": "plan.plan_name" },
43+
{ "data": "plan.major" },
44+
{ "data": "plan.catalog.year"},
45+
{ "data": "open" }
46+
],
47+
"paging": false,
48+
});
49+
$('.dataTables_scrollHeadInner').css('padding', '0');
50+
planTableLoaded = true;
51+
}
52+
});
53+
}
54+
55+
// For loading a single plan
56+
window.getPlan = function(){
57+
$.get("/plans.json", function(plans){
58+
plan = null;
3059
$(".dropdown").html("<option selected disabled>Change Plan</option>");
60+
// set current plan
3161
for (let i in plans){
3262
if (plans[i].major === selectedMajor && plans[i].catalog.year === selectedCatalogYear){
3363
plan = plans[i];
@@ -37,10 +67,11 @@ function getPlans(){
3767
$(".dropdown").append("<option>" + plans[i].major + ", " + plans[i].catalog.year + "</option>");
3868
}
3969
}
40-
if (plan === false){
70+
if (plan == null){
4171
console.log("Error: did not find selected plan");
4272
}
4373

74+
// dynamically generate years, terms, semesters on page
4475
currPlan = new Plan(plan.user.login, plan.plan_name, plan.major, plan.curr_year, plan.curr_term, plan.courses, plan.catalog.year);
4576
currPlan.sortCourses();
4677
currPlan.generateHTML();
@@ -52,6 +83,7 @@ function getPlans(){
5283
$("#hrsFuture").html("Remaining Hours: " + currPlan.hrsFuture);
5384
$("#hrsTotal").html("Total Hours Planned: " + currPlan.hrsTotal);
5485

86+
// load catalog table
5587
let courses = [];
5688
for (let c in plan.catalog.courses){
5789
courses.push(plan.catalog.courses[c]);
@@ -68,7 +100,7 @@ function getPlans(){
68100
],
69101
"scrollY": "95px",
70102
"paging": false,
71-
"scrollCollapse": false
103+
"scrollCollapse": false
72104
});
73105
$('.dataTables_scrollHeadInner').css('padding', '0');
74106
catalogLoaded = true;
@@ -79,12 +111,11 @@ function getPlans(){
79111
}
80112

81113

114+
// load accordion with requirements
82115
var requirements = plan.requirements;
83-
84116
$( function() {
85117
$( "#accordion" ).accordion({collapsible: true, active: false});
86118
});
87-
88119
$('#accordion').empty();
89120
for (let i in requirements){
90121
let reqCourses = requirements[i].courses;
@@ -102,87 +133,119 @@ function getPlans(){
102133
});
103134
}
104135

136+
// check if course is already in the plan
105137
function courseInPlan(designator){
106-
let c = plan.courses[designator];
138+
let c = currPlan.courses[designator];
107139
return c !== undefined;
108140
}
109141

142+
// check if course is already in the semester being dropped on
143+
function courseInSemester(designator, droppedTerm){
144+
for (let i=0; i < droppedTerm.children.length; i++){
145+
if (droppedTerm.children[i].innerText.includes(designator)){
146+
return true;
147+
}
148+
}
149+
return false;
150+
}
151+
152+
// set source course when dragging from requiremetns accordion
110153
window.dragFromReq = function(event){
111154
let desig = event.target.innerText.split(": ")[0];
112155
draggedCourse = plan.catalog.courses[desig];
113156
draggedPlanOrigin = null;
157+
draggedCatOrigin = null;
114158
draggedReqOrigin = event.target;
115159
}
116160

161+
// set source course when dragging from catalog table
117162
window.dragFromCat = function(event){
118163
let desig = event.target.children[0].innerText
119164
draggedCourse = plan.catalog.courses[desig];
120165
draggedPlanOrigin = null;
121166
draggedReqOrigin = null;
167+
draggedCatOrigin = event.target;
122168
}
123169

170+
// set source course when dragging from plan
124171
window.dragFromPlan = function(event){
125172
let desig = event.target.innerText.split(": ")[0];
126173
draggedCourse = plan.catalog.courses[desig];
127174
draggedReqOrigin = null;
175+
draggedCatOrigin = null;
128176
draggedPlanOrigin = event.target;
129177
}
130178

179+
// indicate valid drop when hovering over plan
131180
window.hoverOverPlan = function(event){
132181
event.preventDefault();
133182
}
134183

184+
// update db when dropping course on plan
135185
window.dropOnPlan = function(event){
136186
event.preventDefault();
137-
event.target.children[1].innerHTML += "<li draggable='true' ondragstart='dragFromPlan(event)'>" + draggedCourse.designator + ": " + draggedCourse.name + "</li>";
138-
if (event.target.classList.contains('current')){
139-
currPlan.hrsCurrent += draggedCourse.credits;
140-
}
141-
else if (event.target.classList.contains('notStarted')){
142-
currPlan.hrsFuture += draggedCourse.credits;
143-
}
144-
else{
145-
currPlan.hrsCompleted += draggedCourse.credits;
146-
}
147-
let hours = parseInt(event.target.children[0].children[1].innerText.split(": ")[1]);
148-
event.target.children[0].children[1].innerText = "Hours: " + (hours + draggedCourse.credits);
149-
if (draggedReqOrigin !== null){
150-
// From requirements accordion
151-
currPlan.hrsTotal += draggedCourse.credits;
152-
draggedReqOrigin.hidden = true;
153-
draggedReqOrigin = null;
154-
}
155-
else if (draggedPlanOrigin !== null){
156-
// From another term
157-
if (draggedPlanOrigin.parentElement.parentElement.classList.contains('current')){
158-
currPlan.hrsCurrent -= draggedCourse.credits;
187+
if (!(courseInSemester(draggedCourse.designator, event.target.children[1]) || (courseInPlan(draggedCourse.designator) && draggedCatOrigin != null))) {
188+
event.target.children[1].innerHTML += "<li draggable='true' ondragstart='dragFromPlan(event)'>" + draggedCourse.designator + ": " + draggedCourse.name + "</li>";
189+
if (event.target.classList.contains('current')){
190+
currPlan.hrsCurrent += draggedCourse.credits;
159191
}
160-
else if (draggedPlanOrigin.parentElement.parentElement.classList.contains('notStarted')){
161-
currPlan.hrsFuture -= draggedCourse.credits;
192+
else if (event.target.classList.contains('notStarted')){
193+
currPlan.hrsFuture += draggedCourse.credits;
162194
}
163195
else{
164-
currPlan.hrsCompleted -= draggedCourse.credits;
196+
currPlan.hrsCompleted += draggedCourse.credits;
165197
}
166-
let originHours = parseInt(draggedPlanOrigin.parentElement.previousSibling.children[1].innerText.split(": ")[1]);
167-
draggedPlanOrigin.parentElement.previousSibling.children[1].innerText = "Hours: " + (originHours - draggedCourse.credits);
168-
draggedPlanOrigin.remove();
169-
draggedPlanOrigin = null;
170-
}
171-
else{
172-
// From catalog table
173-
currPlan.hrsTotal += draggedCourse.credits;
198+
let hours = parseInt(event.target.children[0].children[1].innerText.split(": ")[1]);
199+
event.target.children[0].children[1].innerText = "Hours: " + (hours + draggedCourse.credits);
200+
if (draggedReqOrigin !== null){
201+
// From requirements accordion
202+
currPlan.hrsTotal += draggedCourse.credits;
203+
draggedReqOrigin.hidden = true;
204+
draggedReqOrigin = null;
205+
}
206+
else if (draggedPlanOrigin !== null){
207+
// From another term
208+
if (draggedPlanOrigin.parentElement.parentElement.classList.contains('current')){
209+
currPlan.hrsCurrent -= draggedCourse.credits;
210+
}
211+
else if (draggedPlanOrigin.parentElement.parentElement.classList.contains('notStarted')){
212+
currPlan.hrsFuture -= draggedCourse.credits;
213+
}
214+
else{
215+
currPlan.hrsCompleted -= draggedCourse.credits;
216+
}
217+
let originHours = parseInt(draggedPlanOrigin.parentElement.previousSibling.children[1].innerText.split(": ")[1]);
218+
draggedPlanOrigin.parentElement.previousSibling.children[1].innerText = "Hours: " + (originHours - draggedCourse.credits);
219+
draggedPlanOrigin.remove();
220+
draggedPlanOrigin = null;
221+
}
222+
else{
223+
// From catalog table
224+
currPlan.hrsTotal += draggedCourse.credits;
225+
removeFromRequirements(draggedCourse.designator);
226+
}
227+
// add to javascript plan object
228+
let destTerm = event.target.children[0].children[0].innerText.split(" ")[0];
229+
let destYear = parseInt(event.target.children[0].children[0].innerText.split(" ")[1]);
230+
let newCourse = {
231+
"designator": draggedCourse.designator,
232+
"term": destTerm,
233+
"year": destYear
234+
};
235+
currPlan.courses[draggedCourse.designator] = newCourse;
236+
//update db
237+
$.post("/plan_courses", {
238+
plan: plan.plan_name,
239+
user: plan.user.id,
240+
designator: draggedCourse.designator,
241+
term: destTerm,
242+
year: destYear
243+
});
244+
$("#hrsCompleted").html("Hours Completed: " + currPlan.hrsCompleted);
245+
$("#hrsCurrent").html("Current Hours: " + currPlan.hrsCurrent);
246+
$("#hrsFuture").html("Remaining Hours: " + currPlan.hrsFuture);
247+
$("#hrsTotal").html("Total Hours Planned: " + currPlan.hrsTotal);
174248
}
175-
$.post("/plan_courses", {
176-
plan: plan.plan_name,
177-
user: plan.user.id,
178-
designator: draggedCourse.designator,
179-
term: event.target.children[0].children[0].innerText.split(" ")[0],
180-
year: parseInt(event.target.children[0].children[0].innerText.split(" ")[1]),
181-
});
182-
$("#hrsCompleted").html("Hours Completed: " + currPlan.hrsCompleted);
183-
$("#hrsCurrent").html("Current Hours: " + currPlan.hrsCurrent);
184-
$("#hrsFuture").html("Remaining Hours: " + currPlan.hrsFuture);
185-
$("#hrsTotal").html("Total Hours Planned: " + currPlan.hrsTotal);
186249
draggedCourse = null;
187250
}
188251

@@ -206,6 +269,7 @@ window.dropInTrash = function(event){
206269
let originHours = parseInt(draggedPlanOrigin.parentElement.previousSibling.children[1].innerText.split(": ")[1]);
207270
draggedPlanOrigin.parentElement.previousSibling.children[1].innerText = "Hours: " + (originHours - draggedCourse.credits);
208271
draggedPlanOrigin.remove();
272+
delete currPlan.courses[draggedCourse.designator];
209273
draggedPlanOrigin = null;
210274

211275
$.get("/plan_courses", {
@@ -217,10 +281,42 @@ window.dropInTrash = function(event){
217281
$("#hrsCurrent").html("Current Hours: " + currPlan.hrsCurrent);
218282
$("#hrsFuture").html("Remaining Hours: " + currPlan.hrsFuture);
219283
$("#hrsTotal").html("Total Hours Planned: " + currPlan.hrsTotal);
284+
285+
addToRequirements(draggedCourse.designator);
220286
}
221287
draggedCourse = null;
222288
}
223289

290+
// Unhide requirement if removed from plan
291+
window.addToRequirements = function(designator){
292+
let acc = $('#accordion').get()[0];
293+
for (let i=1; i<acc.children.length; i+=2){
294+
let accChild = acc.children[i];
295+
for (let j = 0; j<accChild.children.length; j++){
296+
let req = accChild.children[j];
297+
if (req.innerText.includes(designator)){
298+
req.removeAttribute('hidden');
299+
return;
300+
}
301+
}
302+
}
303+
}
304+
305+
// Hide requirement if added from catalog table
306+
window.removeFromRequirements = function(designator){
307+
let acc = $('#accordion').get()[0];
308+
for (let i=1; i<acc.children.length; i+=2){
309+
let accChild = acc.children[i];
310+
for (let j = 0; j<accChild.children.length; j++){
311+
let req = accChild.children[j];
312+
if (req.innerText.includes(designator)){
313+
req.setAttribute('hidden', true);
314+
return;
315+
}
316+
}
317+
}
318+
}
319+
224320
class Course {
225321
constructor(desig, year, term){
226322
this.term = term;

app/models/user.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ class User < ApplicationRecord
44
devise :database_authenticatable, :registerable,
55
:recoverable, :rememberable, :validatable
66
has_many :plans
7-
belongs_to :major
7+
belongs_to :major, optional: true
88
end

app/views/plans/_plan.json.jbuilder

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ json.user do
33
json.login plan.user.login
44
json.role plan.user.role
55
end
6+
json.id plan.id
67
json.plan_name plan.name
78
json.major plan.major.name
89
json.curr_year plan.curr_year

0 commit comments

Comments
 (0)