codecombat/app/templates/courses/teacher-class-view.jade
Matt Lott d72e4eb750 Practice levels Ux and next level algorithm
Update classroom and gameplay Ux to surface practice levels as 3a, 3b,
etc.
Update next level logic to leverage practice levels based on per level
completion playtime thresholds.
Patrol buster and patrol buster A are live for testing.
Fix a few classroom Ux progress hover bubble info bugs.

Closes #3767
2016-06-27 14:05:42 -07:00

431 lines
17 KiB
Text

extends /templates/base-flat
block page_nav
include ./teacher-dashboard-nav.jade
block content
- var classroom = view.classroom
if !me.isTeacher()
.alert.alert-danger.text-center
.container
// DNT: Temporary
h3 ATTENTION: Please upgrade your account to a Teacher Account.
p
| We are transitioning to a new improved classroom management system for instructors.
| Please convert your account to ensure you retain access to your classrooms.
a.btn.btn-primary.btn-lg(href="/teachers/update-account") Upgrade to teacher account
if classroom.loaded
.container
+breadcrumbs
if classroom.get('archived')
.row.center-block.text-center.m-t-3.m-b-3
.unarchive-btn.btn.btn-lg.btn-navy
span(data-i18n='teacher.unarchive_this_class')
h3.m-t-2= classroom.get('name')
a.label.edit-classroom(data-classroom-id=classroom.id)
span(data-i18n='teacher.edit_class_settings')
h4= classroom.get('description')
.classroom-info-row.row.m-t-5
.classroom-details.col-md-3
- var stats = state.get('classStats')
h4.m-b-2(data-i18n='teacher.class_overview')
.language.small-details
span(data-i18n='teacher.language')
span.spr :
span= classroom.capitalLanguage
.student-count.small-details
span(data-i18n='teacher.students')
span.spr :
span= classroom.get('members').length
.average-playtime.small-details
span(data-i18n='teacher.avg_playtime')
span.spr :
span= stats.averagePlaytime
.total-playtime.small-details
span(data-i18n='teacher.total_playtime')
span.spr :
span= stats.totalPlaytime
.average-complete.small-details
span(data-i18n='teacher.avg_completed')
span.spr :
span= stats.averageLevelsComplete
.total-complete.small-details
span(data-i18n='teacher.total_completed')
span.spr :
span= stats.totalLevelsComplete
.total-complete.small-details
span(data-i18n='teacher.created')
span.spr :
span= moment(classroom.created()).format('l')
if view.students && view.students.models.length > 0
button.export-student-progress-btn.btn.btn-lg.btn-primary
span(data-i18n='teacher.export_student_progress')
//- .concepts.small-details
//- if state.get('progressData')
//- div
//- span(data-i18n='teacher.concepts_covered')
//- span :
//- - console.log('concepts', view.conceptData)
//- - concepts = view.conceptData
//- each state, name in view.conceptData[view.classroom.id]
//- if state.get('started')
//- b.concept(class=state.get('completed') ? 'forest' : 'gold')
//- span(data-i18n='concepts.'+name)
.completeness-info.col-md-4
h4.m-b-2
 
if state.get('earliestIncompleteLevel')
div.small-details
span(data-i18n='teacher.earliest_incomplete')
span :
+longLevelName(state.get('earliestIncompleteLevel'))
+inlineUserList(state.get('earliestIncompleteLevel').users)
if state.get('latestCompleteLevel')
div.small-details.m-t-3
span(data-i18n='teacher.latest_complete')
span :
+longLevelName(state.get('latestCompleteLevel'))
+inlineUserList(state.get('latestCompleteLevel').users)
.adding-students.col-md-5
h4.m-b-2
span(data-i18n='teacher.adding_students')
span :
+copyCodes
+addStudentsButton
if view.students.length > 0
ul.nav.nav-tabs.m-t-5(role='tablist')
- var activeTab = state.get('activeTab');
li(class=(activeTab === "#students-tab" ? 'active' : ''))
a.students-tab-btn(href='#students-tab')
.small-details.text-center(data-i18n='teacher.students')
.tab-spacer
li(class=(activeTab === "#course-progress-tab" ? 'active' : ''))
a.course-progress-tab-btn(href='#course-progress-tab')
.small-details.text-center(data-i18n='teacher.course_progress')
.tab-spacer
li(class=(activeTab === "#enrollment-status-tab" ? 'active' : ''))
a.course-progress-tab-btn(href='#enrollment-status-tab')
.small-details.text-center(data-i18n='teacher.enrollment_status')
.tab-filler
.tab-content
if activeTab === '#students-tab'
+studentsTab
else if activeTab === '#course-progress-tab'
+courseProgressTab
else
+enrollmentStatusTab
else
.text-center.m-t-5.m-b-5
.text-h2
span(data-i18n="teacher.no_students_yet")
.text-h4
span(data-i18n="teacher.try_refreshing")
mixin breadcrumbs
.breadcrumbs
a(data-i18n='teacher.my_classes' href='/teachers/classes')
span.spl.spr >
//- TODO: Use .glyphicon-menu-right when we update bootstrap
span
= view.classroom.get('name')
mixin longLevelName(data)
if data
div.level-name
span.spr Course
span= data.courseNumber
span.spr , Level
span= data.levelNumber
span.spr :
span= data.levelName
else
div.level-name(data-i18n='teacher.not_applicable')
mixin inlineUserList(users)
if users
ul.inline-student-list.small
each student in users
li
//- a(href='TODO')
//- = student.broadName()
span.inline-student-name
= student.broadName()
mixin addStudentsButton
.add-students.text-center
a.add-students-btn.btn.btn-lg.btn-primary(data-classroom-id=view.classroom.id)
span(data-i18n='teacher.add_students_manually')
mixin studentsTab
#students-tab
+bulkAssignControls
table.students-table
thead
th.checkbox-col.select-all.small.text-center
span(data-i18n="teacher.select_all")
.checkbox-flat
input(type='checkbox' id='checkbox-all-students')
label.checkmark(for='checkbox-all-students')
th
+sortButtons
tbody
each student in state.get('students').models
+studentRow(student)
mixin sortButtons
.sort-buttons.small
span(data-i18n='teacher.sort_by')
span.spr :
button.sort-button.sort-by-name(data-i18n='general.name', value='name')
button.sort-button.sort-by-progress(data-i18n='teacher.progress', value='progress')
mixin studentRow(student)
tr.student-row.alternating-background
td.checkbox-col.student-checkbox
.checkbox-flat
input(type='checkbox' id='checkbox-student-' + student.id, data-student-id=student.id)
label.checkmark(for='checkbox-student-' + student.id)
td.student-info-col
.student-info
if student.get('deleted')
em (deleted)
div.student-name= student.broadName()
div.student-email.small-details= student.get('email')
td.hidden
a.edit-student-button(data-student-id=student.id)
span.glyphicon.glyphicon-edit
span(data-i18n='teacher.edit')
td.latest-level-col.small
div
i
span(data-i18n='teacher.latest_completed')
span :
div
+longLevelName(student.latestCompleteLevel)
td
if state.get('progressData')
each trimCourse, index in view.classroom.get('courses')
- var course = view.courses.get(trimCourse._id);
- var instance = view.courseInstances.findWhere({ courseID: course.id, classroomID: classroom.id })
if instance && instance.hasMember(student)
- var progress = state.get('progressData').get({ classroom: view.classroom, course: course, user: student })
- var levelsTotal = trimCourse.levels.length
//- - var level = ???
+studentCourseProgressDot(progress, levelsTotal, level, 'CS' + (index+1))
unless student.isEnrolled()
+enrollStudentButton(student)
//- td
//- span.view-class-arrow.glyphicon.glyphicon-chevron-right
td
.pull-right
a.edit-student-link.small.center-block.text-center.m-r-2(data-student-id=student.id)
div.glyphicon.glyphicon-edit
div(data-i18n='teacher.edit')
a.remove-student-link.small.center-block.text-center.m-r-2(data-student-id=student.id)
div.glyphicon.glyphicon-remove
div(data-i18n='teacher.remove')
mixin enrollStudentButton(student)
a.enroll-student-button.btn.btn-lg.btn-primary(data-classroom-id=view.classroom.id data-user-id=student.id data-event-action="Teachers Class Students Enroll Student")
span(data-i18n='teacher.enroll_student')
mixin courseProgressTab
#course-progress-tab.m-t-3
if view.courses
.text-center
span(data-i18n='teacher.select_course')
span.spr :
select.course-select
each trimCourse in view.classroom.get('courses')
- var course = view.courses.get(trimCourse._id);
option(value=course.id selected=(course===state.get('selectedCourse')))
= course.get('name')
if state.get('progressData')
.render-on-course-sync
+courseOverview
.student-levels-table
+sortButtons
each student in state.get('students').models
if _.contains(state.get('selectedCourse').members, student.id)
+studentLevelsRow(student)
//- TODO: If any students aren't assigned the course
.unassigned-students.render-on-course-sync
if state.get('selectedCourse') && state.get('selectedCourse').members.length < state.get('students').length
h2
span(data-i18n='TODO')
| Students who have not been assigned
|
span= state.get('selectedCourse').get('name')
for student in state.get('students').models
unless _.contains(state.get('selectedCourse').members, student.id)
.row.unassigned-student-row.alternating-background
.student-name.col-sm-3
= student.broadName()
.student-email.small-details.col-sm-3
= student.get('email')
.col-sm-4
.latest-completed.truncate.small
i.m-r-1
span(data-i18n='TODO')
| Latest completed
| :
+longLevelName(student.latestCompleteLevel)
.col-sm-2
if student.isEnrolled()
.assign-student-button.btn.btn-md.btn-navy.pull-right(data-user-id=student.id data-course-id=state.get('selectedCourse').id)
span(data-i18n='TODO')
| Assign Course
else
.enroll-student-button.btn.btn-md.btn-navy.pull-right(data-user-id=student.id data-event-action="Teachers Class Course Enroll Student")
span(data-i18n='TODO')
| Enroll Student
mixin courseOverview
- var course = state.get('selectedCourse')
- var levels = view.classroom.getLevels({courseID: course.id}).models
.course-overview-row
.course-title.student-name
span= course.get('name')
span :
span(data-i18n='teacher.course_overview')
.course-overview-progress
each level, index in levels
- var progress = state.get('progressData').get({ classroom: view.classroom, course: course, level: level })
- var levelNumber = view.classroom.getLevelNumber(level.get('original'), index + 1)
+allStudentsLevelProgressDot(progress, level, levelNumber)
mixin studentLevelsRow(student)
.student-levels-row.alternating-background
div.student-info
div.student-name= student.broadName()
div.student-email.small-details= student.get('email')
div.student-levels-progress
- var course = state.get('selectedCourse')
- var levels = view.classroom.getLevels({courseID: course.id}).models
each level, index in levels
- var progress = state.get('progressData').get({ classroom: view.classroom, course: course, level: level, user: student })
- var levelNumber = view.classroom.getLevelNumber(level.get('original'), index + 1)
+studentLevelProgressDot(progress, level, levelNumber, session)
mixin studentCourseProgressDot(progress, levelsTotal, level, label)
//- TODO: Refactor with TeacherClassesView jade
//- TODO: Give classes abbreviations instead of using index?
- dotClass = progress.completed ? 'forest' : (progress.started ? 'gold' : '');
- _.assign(progress, { levelsTotal: levelsTotal })
.progress-dot(class=dotClass, data-html='true', data-title=view.singleStudentCourseProgressDotTemplate(progress))
+progressDotLabel(label)
mixin allStudentsLevelProgressDot(progress, level, levelNumber)
- dotClass = progress.completed ? 'forest' : (progress.started ? 'gold' : '');
- levelName = level.get('name')
- context = _.merge(progress, { levelName: levelName, levelNumber: levelNumber, numStudents: view.students.length })
.progress-dot.level-progress-dot(class=dotClass, data-html='true', data-title=view.allStudentsLevelProgressDotTemplate(context))
+progressDotLabel(levelNumber)
mixin studentLevelProgressDot(progress, level, levelNumber)
//- TODO: Refactor with TeacherClassesView jade
- dotClass = progress.completed ? 'forest' : (progress.started ? 'gold' : '');
- levelName = level.get('name')
- context = _.merge(progress, { levelName: levelName, levelNumber: levelNumber, moment: moment })
.progress-dot.level-progress-dot(class=dotClass, data-html='true', data-title=view.singleStudentLevelProgressDotTemplate(context))
+progressDotLabel(levelNumber)
mixin progressDotLabel(label)
.dot-label.text-center
.dot-label-inner
= label
mixin copyCodes
div.copy-button-group.form-inline.m-b-3
.form-group
input.text-h4.semibold#join-code-input(value=state.get('classCode'))
button#copy-code-btn.form-control.btn.btn-lg.btn-forest
span(data-i18n='teacher.copy_class_code')
div.text-center.small(data-i18n='teacher.class_code_blurb')
div.copy-button-group.form-inline.m-b-3
.form-group
input.form-control.text-h4.semibold#join-url-input(value=state.get('joinURL'))
button#copy-url-btn.form-control.btn.btn-lg.btn-forest
span(data-i18n='teacher.copy_class_url')
div.text-center.small(data-i18n='teacher.class_join_url_blurb')
mixin bulkAssignControls
.bulk-assign-controls.form-inline
.no-students-selected.small-details(class=state.get('errors').assigningToNobody ? 'visible' : '')
span(data-i18n='teacher.no_students_selected')
.cant-assign-to-unenrolled.small-details(class=state.get('errors').assigningToUnenrolled ? 'visible' : '')
span(data-i18n='teacher.cant_assign_to_unenrolled')
span.small
span(data-i18n='teacher.bulk_assign')
span :
select.bulk-course-select.form-control
each trimCourse in _.rest(view.classroom.get('courses'))
- var course = view.courses.get(trimCourse._id)
option(value=course.id selected=(course===state.get('selectedCourse')))
= course.get('name')
button.btn.btn-primary-alt.assign-to-selected-students
span(data-i18n='teacher.assign_to_selected_students')
button.btn.btn-primary-alt.enroll-selected-students
span(data-i18n='teacher.enroll_selected_students')
mixin enrollmentStatusTab
// TODO: Have search input in all tabs
//form.form-inline.text-center.m-t-3
// #search-form-group.form-group
// label(for="student-search") Search for student:
// input#student-search.form-control.m-l-1(type="search")
// span.glyphicon.glyphicon-search.form-control-feedback
table.table#enrollment-status-table.table-condensed.m-t-3
thead
// Checkbox code works, but don't need it yet.
//th.checkbox-col.select-all
.checkbox-flat
input(type='checkbox' id='checkbox-all-students')
label.checkmark(for='checkbox-all-students')
th
.sort-buttons.small
span(data-i18n='teacher.sort_by')
span.spr :
button.sort-button.sort-by-name(data-i18n='general.name', value='name')
button.sort-button.sort-by-status(data-i18n='user.status', value='status')
tbody
- var searchTerm = view.state.get('searchTerm');
each student in state.get('students').search(searchTerm)
- var status = student.prepaidStatus()
tr.student-row.alternating-background
//td.checkbox-col.student-checkbox
.checkbox-flat
input(type='checkbox' id='checkbox-student-' + student.id, data-student-id=student.id)
label.checkmark(for='checkbox-student-' + student.id)
td.student-info-col
.student-info
div.student-name= student.broadName()
div.student-email.small-details= student.get('email')
td.status-col
span(data-i18n='user.status')
span.spr :
strong(class= status === 'expired' ? 'text-danger' : '')= view.studentStatusString(student)
td.enroll-col
if status !== 'enrolled'
button.enroll-student-button.btn.btn-navy(data-i18n="teacher.enroll_student", data-user-id=student.id, data-event-action="Teachers Class Enrollment Enroll Student")