From b6472529563c5cd088875392149c495868640f14 Mon Sep 17 00:00:00 2001 From: Matt Lott Date: Wed, 17 Aug 2016 14:15:36 -0700 Subject: [PATCH 1/2] Update /courses UI --- app/core/NameLoader.coffee | 5 +++- app/locale/en.coffee | 9 ++++--- app/models/Classroom.coffee | 2 ++ app/styles/courses/courses-view.sass | 8 ++++++- app/templates/courses/courses-view.jade | 31 +++++++++++++------------ app/views/courses/CoursesView.coffee | 11 ++++++++- 6 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/core/NameLoader.coffee b/app/core/NameLoader.coffee index e661b41bf..08b0fc900 100644 --- a/app/core/NameLoader.coffee +++ b/app/core/NameLoader.coffee @@ -18,6 +18,9 @@ class NameLoader extends CocoClass loadedNames: (newNames) => _.extend namesCache, newNames - getName: (id) -> namesCache[id]?.name or id + getName: (id) -> + if namesCache[id]?.firstName and namesCache[id]?.lastName + return "#{namesCache[id]?.firstName} #{namesCache[id]?.lastName}" + namesCache[id]?.firstName or namesCache[id]?.name or id module.exports = new NameLoader() diff --git a/app/locale/en.coffee b/app/locale/en.coffee index adc6f5843..a9265de3b 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -1235,7 +1235,7 @@ play_now_learn_2: "while loops to solve pesky puzzles" play_now_learn_3: "strings & variables to customize actions" play_now_learn_4: "how to defeat an ogre (important life skills!)" - welcome_to_page: "Welcome to your Courses page!" + welcome_to_page: "My Student Dashboard" # {change} completed_hoc: "Amazing! You've completed the Hour of Code course!" ready_for_more_header: "Ready for more? Play the campaign mode!" ready_for_more_1: "Use gems to unlock new items!" @@ -1243,10 +1243,9 @@ ready_for_more_3: "Learn even more programming!" saved_games: "Saved Games" hoc: "Hour of Code" - my_classes: "My Classes" + my_classes: "Current Classes" # {change} class_added: "Class successfully added!" - view_class: "view class" - view_levels: "view levels" + view_levels: "view all levels in course" # {change} join_class: "Join A Class" join_class_2: "Join class" ask_teacher_for_code: "Ask your teacher if you have a CodeCombat class code! If so, enter it below:" @@ -1257,7 +1256,7 @@ play_arena: "Play Arena" view_project: "View Project" start: "Start" - last_level: "Last Level" + last_level: "Last level played" # {change} welcome_to_hoc: "Adventurers, welcome to our Hour of Code!" logged_in_as: "Logged in as:" not_you: "Not you?" diff --git a/app/models/Classroom.coffee b/app/models/Classroom.coffee index 3f57303e4..3016f45c3 100644 --- a/app/models/Classroom.coffee +++ b/app/models/Classroom.coffee @@ -132,6 +132,7 @@ module.exports = class Classroom extends CocoModel complete = session.get('state').complete ? false playtime += session.get('playtime') ? 0 lastPlayed = level + lastPlayedNumber = index + 1 if complete currentIndex = index else @@ -161,6 +162,7 @@ module.exports = class Classroom extends CocoModel numDone: levelsTotal - levelsLeft pctDone: (100 * (levelsTotal - levelsLeft) / levelsTotal).toFixed(1) + '%' lastPlayed: lastPlayed + lastPlayedNumber: lastPlayedNumber ? 1 next: nextLevel first: courseLevels.first() arena: arena diff --git a/app/styles/courses/courses-view.sass b/app/styles/courses/courses-view.sass index 0189b033d..1ca481d4d 100644 --- a/app/styles/courses/courses-view.sass +++ b/app/styles/courses/courses-view.sass @@ -16,6 +16,12 @@ hr border-top: 1px solid grey margin: 5px 0 + padding-bottom: 20px + opacity: 0.5 + + .view-levels-btn + font-size: 13px + padding-left: 10px .text-uppercase margin-top: 40px @@ -29,7 +35,7 @@ padding: 0 20px .course-instance-entry - padding-left: 40px + padding-bottom: 10px .progress-bar min-width: 15% diff --git a/app/templates/courses/courses-view.jade b/app/templates/courses/courses-view.jade index b98c4361f..df1bae58e 100644 --- a/app/templates/courses/courses-view.jade +++ b/app/templates/courses/courses-view.jade @@ -38,7 +38,7 @@ block content else .text-center - h1(data-i18n="courses.welcome_to_page") Welcome to your Courses page! + h1(data-i18n="courses.welcome_to_page") .current-hero-container.text-center.row .hero-avatar @@ -51,10 +51,11 @@ block content span(data-i18n="courses.change_hero") if view.classrooms.size() - h3.text-uppercase(data-i18n="courses.my_classes") - hr - + br + h3(data-i18n="courses.my_classes") + for classroom in view.classrooms.models + hr.class-break - var justAdded = classroom.id === view.classroomJustAdded; - var classroomClass = justAdded ? 'just-added' : ''; if justAdded @@ -65,8 +66,12 @@ block content h5 span.spr= classroom.get('name') span.spr (#{(classroom.get('aceConfig') || {}).language === 'javascript' ? 'JavaScript' : 'Python'}) - a.view-class-btn(data-classroom-id=classroom.id, data-i18n="courses.view_class") - + p + span(data-i18n="courses.teacher") + span : + if view.ownerNameMap && view.ownerNameMap[classroom.get('ownerID')] + span.spl= view.ownerNameMap[classroom.get('ownerID')] + - var courseInstances = view.courseInstances.where({classroomID: classroom.id}); for courseInstance in courseInstances @@ -78,7 +83,7 @@ block content a.view-levels-btn(data-course-id=courseInstance.get('courseID'), data-courseinstance-id=courseInstance.id, data-i18n="courses.view_levels") +course-instance-body(courseInstance, classroom) .clearfix - + h3.text-uppercase(data-i18n="courses.join_class") hr @@ -111,11 +116,11 @@ mixin course-instance-body(courseInstance, classroom) - var projectLevel = stats.levels.project; if arenaLevel - var arenaURL = "/play/ladder/"+arenaLevel.get('slug')+"/course/"+courseInstance.id; - a.play-btn.btn.btn-burgandy.btn-lg.m-b-1(data-href=arenaURL, data-level-slug=arenaLevel.get('slug'), data-event-action="Students Play Arena") + a.play-btn.btn.btn-forest-alt.btn-lg.m-b-1(data-href=arenaURL, data-level-slug=arenaLevel.get('slug'), data-event-action="Students Play Arena") span(data-i18n="courses.play_arena") else if projectLevel - var projectURL = "/play/level/"+projectLevel.get('slug')+"?course="+course.id+"&course-instance="+courseInstance.id; - a.play-btn.btn.btn-burgandy.btn-lg.m-b-1(data-href=projectURL, data-level-slug=projectLevel.get('slug'), data-event-action="Students Play Project") + a.play-btn.btn.btn-forest-alt.btn-lg.m-b-1(data-href=projectURL, data-level-slug=projectLevel.get('slug'), data-event-action="Students Play Project") span(data-i18n="courses.view_project") else a.btn.btn-default.btn-lg.m-b-1(disabled=true, data-i18n="courses.course_complete") @@ -130,16 +135,12 @@ mixin course-instance-body(courseInstance, classroom) a.play-btn.btn.btn-navy.btn-lg.m-b-1(data-href=levelURL, data-level-slug=firstLevel.get('slug'), data-event-action="Students Start Course") span(data-i18n="courses.start") - div - span(data-i18n="clans.playtime") - span.spr : - span= moment.duration(stats.playtime, 'seconds').humanize() if stats.levels.lastPlayed div span(data-i18n="courses.last_level") - span.spr : - span= stats.levels.lastPlayed.get('name') + span : #{stats.levels.lastPlayedNumber}. + span.spl= stats.levels.lastPlayed.get('name') .clearfix .progress diff --git a/app/views/courses/CoursesView.coffee b/app/views/courses/CoursesView.coffee index 220920ed3..3fd3741ff 100644 --- a/app/views/courses/CoursesView.coffee +++ b/app/views/courses/CoursesView.coffee @@ -13,6 +13,7 @@ Course = require 'models/Course' Classroom = require 'models/Classroom' Classrooms = require 'collections/Classrooms' LevelSession = require 'models/LevelSession' +NameLoader = require 'core/NameLoader' Campaign = require 'models/Campaign' ThangType = require 'models/ThangType' utils = require 'core/utils' @@ -59,7 +60,7 @@ module.exports = class CoursesView extends RootView @listenTo @hero, 'all', -> @render() window.tracker?.trackEvent 'Students Loaded', category: 'Students', ['Mixpanel'] - + afterInsert: -> super() unless me.isStudent() or (@classCodeQueryVar and not me.isTeacher()) @@ -90,6 +91,14 @@ module.exports = class CoursesView extends RootView @joinClass() else if @classCodeQueryVar and me.isAnonymous() @openModalView(new CreateAccountModal()) + ownerIDs = _.map(@classrooms.models, (c) -> c.get('ownerID')) ? [] + Promise.resolve($.ajax(NameLoader.loadNames(ownerIDs))) + .then(=> + @ownerNameMap = {} + @ownerNameMap[ownerID] = NameLoader.getName(ownerID) for ownerID in ownerIDs + @render?() + ) + onClickLogInButton: -> modal = new AuthModal() From 46e05e893bf48e3ad25df1def9e87e579e4c372f Mon Sep 17 00:00:00 2001 From: Matt Lott Date: Wed, 17 Aug 2016 09:38:43 -0700 Subject: [PATCH 2/2] Redirect students and teachers on sign in Closes #3857 --- app/views/core/AuthModal.coffee | 14 +++++++++++--- .../CreateAccountModal/CreateAccountModal.coffee | 6 +++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/views/core/AuthModal.coffee b/app/views/core/AuthModal.coffee index 3c57f41f3..7a764c580 100644 --- a/app/views/core/AuthModal.coffee +++ b/app/views/core/AuthModal.coffee @@ -51,7 +51,7 @@ module.exports = class AuthModal extends ModalView return forms.applyErrorsToForm(@$el, res.errors) unless res.valid new Promise(me.loginPasswordUser(userObject.emailOrUsername, userObject.password).then) .then(-> - if window.nextURL then window.location.href = window.nextURL else window.location.reload() + if window.nextURL then window.location.href = window.nextURL else loginNavigate() ) .catch((jqxhr) => showingError = false @@ -85,7 +85,7 @@ module.exports = class AuthModal extends ModalView existingUser.fetchGPlusUser(gplusAttrs.gplusID, { success: => me.loginGPlusUser(gplusAttrs.gplusID, { - success: -> window.location.reload() + success: -> loginNavigate() error: @onGPlusLoginError }) error: @onGPlusLoginError @@ -116,7 +116,7 @@ module.exports = class AuthModal extends ModalView existingUser.fetchFacebookUser(facebookAttrs.facebookID, { success: => me.loginFacebookUser(facebookAttrs.facebookID, { - success: -> window.location.reload() + success: -> loginNavigate() error: @onFacebookLoginError }) error: @onFacebookLoginError @@ -148,3 +148,11 @@ formSchema = { } required: ['emailOrUsername', 'password'] } + +loginNavigate = -> + if me.isStudent() + application.router.navigate('/courses', {trigger: true}) + else if me.isTeacher() + application.router.navigate('/teachers/classes', {trigger: true}) + window.location.reload() + diff --git a/app/views/core/CreateAccountModal/CreateAccountModal.coffee b/app/views/core/CreateAccountModal/CreateAccountModal.coffee index 90a4b8fb7..da65e8602 100644 --- a/app/views/core/CreateAccountModal/CreateAccountModal.coffee +++ b/app/views/core/CreateAccountModal/CreateAccountModal.coffee @@ -123,7 +123,11 @@ module.exports = class CreateAccountModal extends ModalView @once 'hidden', -> if @signupState.get('accountCreated') and not application.testing # ensure logged in state propagates through the entire app - document.location.reload() + if me.isStudent() + application.router.navigate('/courses', {trigger: true}) + else if me.isTeacher() + application.router.navigate('/teachers/classes', {trigger: true}) + window.location.reload() onClickLoginLink: -> @openModalView(new AuthModal({ initialValues: @signupState.get('authModalInitialValues') }))