From 3f6fd93eedee7c63e4dc98b6e4f34d54f5ce6e20 Mon Sep 17 00:00:00 2001 From: Kenneth Jao Date: Sat, 8 Apr 2017 16:45:53 -0400 Subject: [PATCH] Finished mobile login page --- hourglass/client/menus/menus.css | 1 + hourglass/client/mobile/mobile.js | 2 +- hourglass/client/profile/mProfile.css | 163 ++++++++++++++++ hourglass/client/profile/mProfile.html | 90 ++++++++- hourglass/client/profile/mProfile.js | 252 +++++++++++++++++++++++++ hourglass/client/profile/profile.css | 1 + hourglass/client/profile/profile.js | 22 ++- hourglass/lib/router.js | 3 +- 8 files changed, 521 insertions(+), 13 deletions(-) create mode 100644 hourglass/client/profile/mProfile.css create mode 100644 hourglass/client/profile/mProfile.js diff --git a/hourglass/client/menus/menus.css b/hourglass/client/menus/menus.css index 5ef3541..edb5b13 100644 --- a/hourglass/client/menus/menus.css +++ b/hourglass/client/menus/menus.css @@ -558,6 +558,7 @@ padding: 0; background-color: transparent; display: inline; + position: relative; } .formDiv:first-child { diff --git a/hourglass/client/mobile/mobile.js b/hourglass/client/mobile/mobile.js index 9917500..0ef16d1 100644 --- a/hourglass/client/mobile/mobile.js +++ b/hourglass/client/mobile/mobile.js @@ -563,7 +563,7 @@ Template.mOptionCard.rendered = function() { }); } -function addMobileButton(element, lighten, animateType, completeFunction) { +addMobileButton = function(element, lighten, animateType, completeFunction) { let add = lighten; let type = animateType; let ele = jQuery(element); diff --git a/hourglass/client/profile/mProfile.css b/hourglass/client/profile/mProfile.css new file mode 100644 index 0000000..741233f --- /dev/null +++ b/hourglass/client/profile/mProfile.css @@ -0,0 +1,163 @@ +#mProfWrapper { + width: 100%; + height: 100%; + + background-color: #282933; + color: #FCF0F0 !important; + position: absolute; +} + +.mSelect { + font-size: 4vw; + width: 100%; + padding: 4.5%; + + border-bottom: 1px solid #888 !important; +} + +#mOpOverlay { + color: #FCF0F0 !important; + height: 100%; + width: 100%; + + background-color: rgba(0,0,0,0.3); + + display: none; + opacity: 0; + + position: absolute; + top: 0; + left: 0; +} + +#mProfMain { + margin-top: 10%; +} + +#schoolCont, #gradeCont, #classCont { + position: relative; +} + +#schoolCont .fa, #gradeCont .fa { + position: absolute; + top: 40%; + right: 4%; + + pointer-events: none; +} + +#classCont .fa { + padding: 0; + position: absolute; + top: 35%; + right: 3%; + + pointer-events: none; +} + +#mOpCont { + width: 70%; + margin: auto; + margin-top: 30%; + background-color: #444; +} + +#mOpCont h3 { + font-weight: 200; + padding: 4%; + + background-color: rgba(255,255,255,0.1); +} + +#mOpProfCont { + max-height: 56vh; + overflow-x: hidden; + overflow-y: auto; +} + +.mOpCard2 { + width: 90%; + padding: 4% 4% 4% 6%; + border-bottom: 1px solid #555; + background-color: rgba(255,255,255,0.01); +} + +#mProfClass { + margin-top: 10%; +} + +#classCont { + padding: 3%; + background-color: rgba(255,255,255,0.2); +} + +#classCont h3 { + font-weight: 100; + pointer-events: none; +} + +.mDisable { + color: #888; +} + +.mClassBox { + width: 90%; + padding: 4% 4% 4% 6%; + + border-bottom: 1px solid #555; + background-color: rgba(255,255,255,0.01); + + display: table; + table-layout: fixed; +} + +.mClassBox .fa { + font-size: 4vw; + width: 2%; + display: table-cell; +} + +#mProfClassTitle { + font-weight: 200; + width: 92%; + padding: 4%; + + background-color: rgba(255,255,255,0.1); + + display: table; +} + +#mProfClassTitle h3 { + width: 40%; + background-color: rgba(0,0,0,0); + display: table-cell; +} + +#mOpProfCont h3 { + background-color: rgba(255,255,255,0); +} + +#mClassSearch { + font-size: 3.5vw; + width: 90%; + padding: 5%; + outline: none; +} + +.-autocomplete-container { + display: none; +} + +#mProfSubmit { + font-size: 4vw; + width: 15vw; + margin: auto; + padding: 3%; + + background-color: rgba(255,255,255,0.2); + text-align: center; + + position: absolute; + bottom: 3vh; + left: 42.5vw; +} \ No newline at end of file diff --git a/hourglass/client/profile/mProfile.html b/hourglass/client/profile/mProfile.html index 7ee731f..77ac012 100644 --- a/hourglass/client/profile/mProfile.html +++ b/hourglass/client/profile/mProfile.html @@ -1,3 +1,89 @@ \ No newline at end of file +
+
+
+
+ + +
+
+ + +
+
+
+
+

My Classes

+ +
+ {{#each mProfClasses}} + {{> mClassDisplay2}} + {{/each}} +
+

Finish!

+
+
+
+ {{#if mProfOp 'class'}} +
+

Select

+ {{> inputAutocomplete id="mClassSearch" settings=classSettings placeholder="Search..."}} +
+
+ {{#if notsearching}} + {{#each classes}} + {{> mClassDisplay}} + {{/each}} + {{#if noclass}} +

No results found...

+ {{/if}} + {{else}} + {{#each autocompleteClasses}} + {{> mClassDisplay}} + {{/each}} + {{#if notfound}} +

No results found...

+ {{/if}} + {{/if}} +
+ {{else}} +

Select

+
+ {{#if mProfOp 'school'}} + {{#each selectOptions 'school'}} + {{> mOptionCard2}} + {{/each}} + {{/if}} + {{#if mProfOp 'grade'}} + {{#each selectOptions 'grade'}} + {{> mOptionCard2}} + {{/each}} + {{/if}} +
+ {{/if}} +
+
+
+ {{> sAlert}} + + + + + + + diff --git a/hourglass/client/profile/mProfile.js b/hourglass/client/profile/mProfile.js new file mode 100644 index 0000000..54aab01 --- /dev/null +++ b/hourglass/client/profile/mProfile.js @@ -0,0 +1,252 @@ +Session.set("profile", {classes: []}); +Session.set("notsearching", true); // If user isn't searching +Session.set("noclass", null); // If user doesn't have classes. +Session.set("autocompleteDivs", null); + +Template.mProfile.rendered = function() { + addMobileButton($("#school"), 0.2, "brightness", function() { + Session.set("mProfOption", "school"); + $("#mOpOverlay").velocity("fadeIn", 200); + }); + + addMobileButton($("#grade"), 0.2, "brightness", function() { + Session.set("mProfOption", "grade"); + $("#mOpOverlay").velocity("fadeIn", 200); + }); + + addMobileButton($("#classCont"), -0.1, "brightness", function() { + if(Session.get("profile").school === undefined) return; + Session.set("mProfOption", "class"); + $("#mOpOverlay").velocity("fadeIn", 200); + }); + + addMobileButton($("#mProfSubmit"), -0.1, "brightness", function() { + var myClasses = Session.get("profile").classes; + var message = "Sorry, your profile couldn't be created. Please try again!"; + + var inputs = document.getElementsByClassName("mSelect"); + var required = ["school","grade"]; + var alert = checkComplete(required, inputs); + var values = alert[2]; + if(!alert[0]) { + sAlert.error("Missing " + alert[1], { + effect: 'stackslide', + position: 'top', + timeout: 3000 + }); + return; + } + + if(myClasses.length === 0) { + sAlert.error("Please enroll in a class!", { + effect: 'stackslide', + position: 'top' + }); + return; + } + + _.each(myClasses, function(myClass) { + Meteor.call("joinClass", [myClass, ""], function(err, result) { + if(err !== undefined) { + sAlert.error(message, { + effect: 'stackslide', + position: 'top' + }); + } + }) + }); + var profile = Session.get("profile"); + profile.complete = true; + profile.preferences = Meteor.user().profile.preferences; + profile.classes.push(Meteor.userId()); + Meteor.call("editProfile", profile, function(err, result) { + if(err !== undefined) { + sAlert.error(message, { + effect: 'stackslide', + position: 'top' + }); + } + Meteor.subscribe('classes'); + Meteor.subscribe('schools'); + Meteor.subscribe('teachers'); + Meteor.subscribe('work'); + Meteor.subscribe('requests'); + Meteor.subscribe("personalUser"); + Meteor.subscribe('users'); + }); + }); +} + +Template.mProfile.helpers({ + mProfOp(type) { + return Session.equals("mProfOption", type); + }, + classes() { + var array = classes.find({ + status: { + $eq: true + }, + privacy: { + $eq: false + }, + _id: { + $nin: Session.get("profile").classes + }, + school: { + $eq: Session.get("profile").school + } + }, { + sort: { + subscribers: -1 + } + }, { + limit: 20 + }).fetch(); + + for (var i = 0; i < array.length; i++) { + array[i].subscribers = array[i].subscribers.length; + array[i].teachershort = array[i].teacher.split(" ").slice(1).reduce(function(a, b) { + return a + " " + b; + }); + } + if (array.length === 0) { + Session.set("noclass", true); + } else { + Session.set("noclass", false); + } + return array; + }, + classSettings() { + return { + position: "bottom", + limit: 10, + rules: [{ + token: '', + collection: classes, + template: Template.classAutoList, + filter: { + privacy: false, + status: true + }, + selector: (match) => { + regex = new RegExp(match, 'i'); + return { + $or: [{ + 'name': regex + }, { + 'teacher': regex + }, { + 'hour': regex + }] + }; + } + }] + }; + }, + notsearching() { // Tells whether user is using the searchbox + return Session.get("notsearching"); + }, + autocompleteClasses() { // Returns current auto-completes for classes + return Session.get("autocompleteDivs"); + }, + notfound() { // Returns if autocomplete has no results. + return Session.get("notfound"); + }, + mProfClasses() { + var array = []; + var myClasses = Session.get("profile").classes; + for(var i = 0; i < myClasses.length; i++) { + var val = classes.findOne({_id: myClasses[i]}); + val.subscribers = val.subscribers.length; + val.teachershort = val.teacher.split(" ").slice(1).reduce(function(a, b) { + return a + " " + b; + }); + array.push(val); + + } + return array; + } +}); + +Template.mProfile.events({ + 'click #mOpOverlay' (event) { + if(event.target.id === "mOpOverlay") { + $("#mOpOverlay").velocity("fadeOut", 200); + } + }, + 'input #mClassSearch' (event) { // Auto-complete updater + if (event.target.value.length === 0) { + Session.set("notsearching", true); + } else { + Session.set("notsearching", false); + } + Session.set("autocompleteDivs", null); + var divs = []; + try { + var items = document.getElementsByClassName("-autocomplete-container")[0].children; + if(items[0].tagName === "I") { + Session.set("notfound", true); + return; + } else { + items = items[0].children; + for(var i = 0; i < items.length; i++) { + var item = items[i].children; + var id = item[4].textContent; + if(Session.get("profile").classes.indexOf(id) !== -1) continue; + divs.push({ + name: item[0].textContent, + teachershort: item[1].textContent.split(" ")[1], + hour: item[2].textContent, + subscribers: (item[3].textContent.match(new RegExp(",","g")) || []).length+1, + _id: id, + join: true + }) + } + Session.set("autocompleteDivs", divs.sort(function(a, b) { + return b.subscribers - a.subscribers; + })); + Session.set("notfound", false); + return; + } + } catch(err) {} + }, +}) + +Template.mOptionCard2.rendered = function() { + var div = this.firstNode; + addMobileButton(div, 0.1, "brightness", function() { + $("#"+Session.get("mProfOption"))[0].value = div.innerHTML; + var newSetting = Session.get("profile"); + if(Session.equals("mProfOption", "school")) { + $("#classCont").removeClass("mDisable"); + if(div.innerHTML !== Session.get("profile").school) { + newSetting["classes"] = []; + } + newSetting[Session.get("mProfOption")] = div.innerHTML; + } else { + newSetting[Session.get("mProfOption")] = div.innerHTML; + } + Session.set("profile", newSetting); + $("#mOpOverlay").velocity("fadeOut", 200); + + }); +} + +Template.mClassDisplay.rendered = function() { + var div = this.firstNode; + addMobileButton(div, 0.1, "brightness", function() { + var newSetting = Session.get("profile"); + newSetting.classes.push(div.getAttribute("classid")); + Session.set("profile", newSetting); + $("#mOpOverlay").velocity("fadeOut", 200); + }); +} + +Template.mClassDisplay2.rendered = function() { + var div = this.firstNode.children[3]; + div.onclick = function() { + var newSetting = Session.get("profile"); + newSetting.classes.splice(newSetting.classes.indexOf(div.getAttribute("classid")),1) + Session.set("profile", newSetting); + } +} \ No newline at end of file diff --git a/hourglass/client/profile/profile.css b/hourglass/client/profile/profile.css index bd3bc5a..c6f385f 100644 --- a/hourglass/client/profile/profile.css +++ b/hourglass/client/profile/profile.css @@ -62,6 +62,7 @@ } #basicNext { + font-weight: 200; padding: 2%; border: 1px solid #FCF0F0; -moz-border-radius: 5px; diff --git a/hourglass/client/profile/profile.js b/hourglass/client/profile/profile.js index 9a55530..6c3122c 100644 --- a/hourglass/client/profile/profile.js +++ b/hourglass/client/profile/profile.js @@ -12,14 +12,6 @@ Session.set("noclass", null); // If user doesn't have classes. Session.set("notfound", null); // If no results for autocomplete. Template.profile.helpers({ - schoolgradenext() { - if(_.contains([null, undefined, ""], Meteor.user().profile.school || - _.contains([null, undefined, ""], Meteor.user().profile.grade))) { - return ""; - } else { - return "disabled"; - } - }, showArrow(type) { var order = [ {"back":false, "forward":true}, @@ -291,6 +283,12 @@ Template.profile.events({ document.getElementById(modifyingInput).value = option; toggleOptionMenu(false, modifyingInput); $(".selectedOption").removeClass("selectedOption"); + if(option !== Session.get("profile").school) { + newSetting = Session.get("profile"); + newSetting["classes"] = []; + newSetting.school = option; + Session.set("profile", newSetting); + } }, 'input #classSearch' (event) { // Auto-complete updater if (event.target.value.length === 0) { @@ -375,6 +373,14 @@ Template.profile.events({ var newClasses = Session.get("newClasses"); var message = "Sorry, your profile couldn't be created. Please try again!"; + if(myClasses.length === 0 && newClasses.length === 0) { + sAlert.error("Please enroll in a class!", { + effect: 'stackslide', + position: 'top' + }); + return; + } + _.each(myClasses, function(myClass) { Meteor.call("joinClass", [myClass, ""], function(err, result) { if(err !== undefined) { diff --git a/hourglass/lib/router.js b/hourglass/lib/router.js index 092e8fc..9318c40 100644 --- a/hourglass/lib/router.js +++ b/hourglass/lib/router.js @@ -31,8 +31,7 @@ Router.route('/', { } else { Session.set("user", Meteor.user().profile); if(Meteor.Device.isPhone()) { - //this.render("mobile"); - this.render("mProfile"); + this.render("mobile"); } else { this.render("main"); }