Add Course Progress Dots and Hovers

This commit is contained in:
Robin Yang 2016-09-15 13:48:26 -07:00
parent ecd82947ec
commit d53f8eba39
3 changed files with 207 additions and 108 deletions

View file

@ -1,3 +1,57 @@
@import "app/styles/bootstrap/variables"
@import "app/styles/mixins"
@import "app/styles/style-flat-variables"
#teacher-student-view
.progress-dot
margin: 5px
.progress-dot
display: inline-block
margin-right: 6px
min-width: 34px
height: 34px
border-radius: 16px
padding: 0 5px
// margin-top: 23px
// margin-bottom: 23px
background: $gray-light
position: relative
a
text-decoration: none
.dot-label
padding-top: 2px
.dot-label-inner
font-size: 11px
font-weight: bold
color: white
.progress-dot-lg .dot-label .dot-label-inner
font-size: 13px
.progress-dot.forest
background: $forest
.tooltip-inner
color: $forest
border-color: $forest
.tooltip-arrow
border-top-color: $forest
.progress-dot.gold
background: $gold
.tooltip-inner
color: $navy
border-color: $navy
.tooltip-arrow
border-top-color: $navy
.progress-dot.navy
background: $navy
.tooltip-inner
color: $navy
border-color: $navy
.tooltip-arrow
border-top-color: $navy

View file

@ -4,107 +4,125 @@ block page_nav
include ../courses/teacher-dashboard-nav.jade
block content
.container
+breadcrumbs
if !me.isAnonymous() && me.isTeacher()
- var isOwner = view.classroom ? view.classroom.get('ownerID') === me.id : false;
// - var validStudent = ...
// load all students in this class
// check if this student is in the class
if !view.user
div Loading
else
.container
+breadcrumbs
if !me.isAnonymous() && me.isTeacher()
- var isOwner = view.classroom ? view.classroom.get('ownerID') === me.id : false;
// - var validStudent = ...
// load all students in this class
// check if this student is in the class
if isOwner
// also check if validStudent
h3 Student Profile:
span= view.user.get('name')
//- - console.log (view.user.get('email'))
// this user object doesn't have an email property
if (view.user.get('email'))
//- - console.log ("User has an email")
p Student Email:
span= view.user.get('email')
else
p
i Student has no email address set.
p Last Level Played:
span= view.lastPlayedString
- var status = view.user.prepaidStatus()
span(data-i18n='view.user.status')
span.spr License Status:
strong(class= status === 'expired' ? 'text-danger' : '')= view.studentStatusString()
if isOwner
// also check if validStudent
h3 Student Profile:
span= view.user.get('name')
p Student Last Played:
span= view.lastPlayedString
h4 Actions:
// Assign courses from dropdown
// Export CSV
// Apply License
// Edit password
// Remove Student
div Here's some course progress!
.student-levels
div.student-levels-progress
each versionedCourse in view.classroom.get('courses') || []
- var course = _.find(view.courses.models, function(c) {return c.id === versionedCourse._id;});
if !course
- continue;
- var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id })
- if (instance && instance.hasMember(view.user))
div.course-info= course.get('name')
- var levels = view.classroom.getLevels({courseID: course.id}).models
each level, index in levels
- var levelNumber = view.classroom.getLevelNumber(level.get('original'), index + 1)
//- - console.log (level)
- var levelProgress = view.levelProgressMap[level.get('original')]
//- p= levelNumber + ". " + level.name + " Progress: " + view.levelProgressMap[level.original]
//- - console.log(level)
+studentLevelProgressDot(levelProgress, level, levelNumber, course)
if status == 'enrolled'
div Student isn't in the following courses!
each versionedCourse in view.classroom.get('courses') || []
- var course = _.find(view.courses.models, function(c) {return c.id === versionedCourse._id;});
if !course
- continue;
- var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id })
- if (!(instance && instance.hasMember(view.user)))
div= course.get('name')
// add a button to assign this course
//- else
//- p Apply a license to this student to assign additional courses!
//- button.enroll-student-button.btn.btn-navy(data-i18n="teacher.apply_license", data-user-id=view.user.id, data-event-action="Teachers Class Enrollment Enroll Student")
//- // this button doesn't work yet
- var status = view.user.prepaidStatus()
span(data-i18n='view.user.status')
span.spr License Status:
strong(class= status === 'expired' ? 'text-danger' : '')= view.studentStatusString()
div Here's some course progress!
table.table
each versionedCourse in view.classroom.get('courses') || []
- var course = _.find(view.courses.models, function(c) {return c.id === versionedCourse._id;});
if !course
- continue;
- var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id })
- if (instance && instance.hasMember(view.user))
th= course.get('name')
each level, index in versionedCourse.levels || []
- var levelNumber = view.classroom.getLevelNumber(level.original, index + 1)
tr
td= levelNumber
td= level.name
td= view.levelProgressMap[level.original]
if status == 'enrolled'
div Student isn't in the following courses!
each versionedCourse in view.classroom.get('courses') || []
- var course = _.find(view.courses.models, function(c) {return c.id === versionedCourse._id;});
if !course
- continue;
- var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id })
- if (!(instance && instance.hasMember(view.user)))
div= course.get('name')
// add a button to assign this course
mixin studentLevelProgressDot(levelProgress, level, levelNumber, course)
//- TODO: Refactor with TeacherClassesView jade
- dotClass = levelProgress == 'complete' ? 'forest' : (levelProgress == 'started' ? 'gold' : '');
- levelName = level.get('name')
- var context = { levelName: levelName, levelNumber: levelNumber, moment: moment , started: levelProgress == 'started', completed: levelProgress == 'complete'};
if view.levelSessionMap && view.levelSessionMap[level.get('original')]
- context.session = view.levelSessionMap[level.get('original')];
- link = null;
- labelText = levelNumber;
if level.isLadder()
- var courseInstance = view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id });
if courseInstance
- link = view.urls.courseArenaLadder({level: level, courseInstance: courseInstance});
- labelText = translate('courses.arena');
else
p Apply a license to this student to assign additional courses!
button.enroll-student-button.btn.btn-navy(data-i18n="teacher.apply_license", data-user-id=view.user.id, data-event-action="Teachers Class Enrollment Enroll Student")
// this button doesn't work yet
//- - var paidFor = view.user.isEnrolled();
//- for courseInstance in view.courseInstances.models
//- - var inCourse = _.contains(courseInstance.get('members'), view.user.id);
//- if !(inCourse || view.teacherMode)
//- - continue;
//- - var course = view.courses.get(courseInstance.get('courseID'));
//- - var sessions = courseInstance.sessionsByUser[view.user.id] || [];
//- if !(course.get('free') || paidFor)
//- - continue;
//- if inCourse
//- .row
//- .col-sm-3.text-right= i18n(course.attributes, 'name')
//- .col-sm-9
//- if inCourse
//- - var levels = view.classroom.getLevels({courseID: course.id});
//- - var numLevels = levels.size();
//- - var sessionMap = _.zipObject(_.map(sessions, function(s) { return s.get('level').original; }), sessions);
//- - var levelCellWidth = 100.00;
//- if numLevels > 0
//- - levelCellWidth = 100.00 / numLevels;
//- - var css = "width:"+levelCellWidth+"%;"
//- - var i = 0;
//- .progress
//- each trimModel in levels.models
//- - var level = view.levels.get(trimModel.get('original')); // get the level loaded through the db
//- if !level
//- - continue;
//- - var levelNumber = view.classroom.getLevelNumber(level.get('original'), i + 1)
//- - i++
//- - var session = sessionMap[level.get('original')];
//- a(href=view.getLevelURL(level, course, courseInstance, session))
//- - var content = view.levelPopoverContent(level, session, levelNumber);
//- if session && session.get('state') && session.get('state').complete
//- .progress-bar.progress-bar-complete(style=css, data-content=content, data-toggle='popover')= levelNumber
//- else if session
//- .progress-bar.progress-bar-started(style=css, data-content=content, data-toggle='popover')= levelNumber
//- else
//- .progress-bar.progress-bar-default(style=css, data-content=content, data-toggle='popover')= levelNumber
//- else if paidFor
//- .text-center
//- button.enable-btn.btn.btn-info.btn-sm.text-uppercase(data-user-id=view.user.id, data-course-instance-cid=courseInstance.cid)
//- span.spr(data-i18n="courses.assign")
//- span= i18n(course.attributes, 'name')
//-
- labelText = translate('courses.arena');
- dotClass += ' progress-dot-lg';
else if level.isProject()
if levelProgress == 'started' || levelProgress == 'complete'
if view.levelSessionMap && view.levelSessionMap[level.get('original')]
- link = view.urls.playDevLevel({level: level, session: view.levelSessionMap[level.get('original')], course: course});
- labelText = translate('teacher.view_student_project');
- dotClass = 'navy';
else
- labelText = translate('teacher.project');
- dotClass += ' progress-dot-lg';
.progress-dot.level-progress-dot(class=dotClass, data-html='true', data-title=view.singleStudentLevelProgressDotTemplate(context))
if link
a(href=link)
+progressDotLabel(labelText)
else
+progressDotLabel(labelText)
mixin progressDotLabel(label)
.dot-label.text-center
.dot-label-inner
= label
mixin breadcrumbs
.breadcrumbs
a(data-i18n='teacher.my_classes' href='/teachers/classes')

View file

@ -23,11 +23,11 @@ module.exports = class TeacherStudentView extends RootView
# helper: helper
events:
'click .assign-student-button': 'onClickAssignStudentButton'
'click .enroll-student-button': 'onClickEnrollStudentButton'
'click .enroll-student-button': 'onClickEnrollStudentButton' # this button isn't working yet
getTitle: -> return @user?.broadName()
initialize: (options, classroomID, studentID) ->
initialize: (options, classroomID, @studentID) ->
@classroom = new Classroom({_id: classroomID})
@listenToOnce @classroom, 'sync', @onClassroomSync
@supermodel.trackRequest(@classroom.fetch())
@ -47,14 +47,35 @@ module.exports = class TeacherStudentView extends RootView
# @levels.fetchForClassroom(classroomID, {data: {project: 'name,original,practice,slug'}})
# @levels.on 'add', (model) -> @_byId[model.get('original')] = model # so you can 'get' them
@supermodel.trackRequest(@levels.fetchForClassroom(classroomID, {data: {project: 'name,original'}}))
#
# @user = new User({_id: studentID})
# @supermodel.trackRequest(@user.fetch())
@user = new User({_id: studentID})
@supermodel.trackRequest(@user.fetch())
@urls = require('core/urls')
@singleStudentLevelProgressDotTemplate = require 'templates/teachers/hovers/progress-dot-single-student-level'
@levelProgressMap = {}
super(options)
onLoaded: ->
if @students.loaded and not @destroyed
@user = _.find(@students.models, (s)=> s.id is @studentID)
@updateLastPlayedString()
@updateLevelProgressMap()
@render()
super()
afterRender: ->
super(arguments...)
$('.progress-dot, .btn-view-project-level').each (i, el) ->
dot = $(el)
dot.tooltip({
html: true
container: dot
}).delegate '.tooltip', 'mousemove', ->
dot.tooltip('hide')
onClassroomSync: ->
# Now that we have the classroom from db, can request all level sessions for this classroom
@ -63,6 +84,12 @@ module.exports = class TeacherStudentView extends RootView
@listenTo @sessions, 'sync', @onSessionsSync
@supermodel.trackRequests(@sessions.fetchForAllClassroomMembers(@classroom))
@students = new Users()
jqxhrs = @students.fetchForClassroom(@classroom, removeDeleted: true)
# @listenTo @students, ->
# console.log @students
@supermodel.trackRequests jqxhrs
onSessionsSync: ->
# Now we have some level sessions, and enough data to calculate last played string
# This may be called multiple times due to paged server API calls via fetchForAllClassroomMembers
@ -97,7 +124,7 @@ module.exports = class TeacherStudentView extends RootView
updateLastPlayedString: ->
# Make sure all our data is loaded, @sessions may not even be intialized yet
return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @user.loaded
return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @user?.loaded
# Use lodash to find the last session for our user, @sessions already sorted by changed date
session = _.findLast @sessions.models, (s) => s.get('creator') is @user.id
@ -128,18 +155,18 @@ module.exports = class TeacherStudentView extends RootView
@render()
updateLevelProgressMap: ->
return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @user.loaded
return unless @courses.loaded and @levels.loaded and @sessions?.loaded and @user?.loaded
# Map levels to sessions once, so we don't have to search entire session list multiple times below
levelSessionMap = {}
for session in @sessions.models
levelSessionMap[session.get('level').original] = session
@levelSessionMap = {}
for session in @sessions.models when session.get('creator') is @studentID
@levelSessionMap[session.get('level').original] = session
# Create mapping of level to student progress
@levelProgressMap = {}
for versionedCourse in @classroom.get('courses') ? []
for versionedLevel in versionedCourse.levels
session = levelSessionMap[versionedLevel.original]
session = @levelSessionMap[versionedLevel.original]
if session
if session.get('state')?.complete
@levelProgressMap[versionedLevel.original] = 'complete'