mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-11 16:21:08 -05:00
ef0547f72a
In TeacherClassView, when a teacher assigns a paid course to any unenrolled student, the view automatically enrolls those students, rather than requiring the teacher to enroll those students manually first. Update copy throughout. Also add back (smaller) padding to progress dots in TeacherClassView.
454 lines
18 KiB
Text
454 lines
18 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.add_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 === "#license-status-tab" ? 'active' : ''))
|
|
a.course-progress-tab-btn(href='#license-status-tab')
|
|
.small-details.text-center(data-i18n='teacher.license_status')
|
|
.tab-filler
|
|
|
|
.tab-content
|
|
if activeTab === '#students-tab'
|
|
+studentsTab
|
|
else if activeTab === '#course-progress-tab'
|
|
+courseProgressTab
|
|
else if activeTab === '#license-status-tab'
|
|
+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= data.courseName + ': '
|
|
span(data-i18n='play_level.level')
|
|
span.spl= data.levelNumber
|
|
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
|
|
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
|
|
- var allStudentsChecked = _.all(state.get('checkboxStates'))
|
|
input(type='checkbox', id='checkbox-all-students', checked=allStudentsChecked)
|
|
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, checked=state.get('checkboxStates')[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')
|
|
div
|
|
+longLevelName(student.latestCompleteLevel)
|
|
td
|
|
if state.get('progressData')
|
|
- var courses = view.sortedCourses.map(function(c) { return view.courses.get(c._id); });
|
|
- var courseLabelsArray = view.helper.courseLabelsArray(courses);
|
|
each trimCourse, index in view.sortedCourses
|
|
- 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 = ???
|
|
- var label = courseLabelsArray[index];
|
|
+studentCourseProgressDot(progress, levelsTotal, level, label)
|
|
//- 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 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.sortedCourses
|
|
- var course = view.courses.get(trimCourse._id);
|
|
option(value=course.id selected=(course===state.get('selectedCourse')))
|
|
= i18n(course.attributes, '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)
|
|
.unassigned-students.render-on-course-sync
|
|
if state.get('selectedCourse') && state.get('selectedCourse').members.length < state.get('students').length
|
|
h2
|
|
- var courseName = i18n(state.get('selectedCourse').attributes, 'name');
|
|
span= translate('teacher.students_not_assigned').replace('{{courseName}}', courseName)
|
|
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='teacher.latest_completed')
|
|
+longLevelName(student.latestCompleteLevel)
|
|
.col-sm-2
|
|
.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='teacher.assign_course')
|
|
|
|
mixin courseOverview
|
|
- var course = state.get('selectedCourse')
|
|
- var levels = view.classroom.getLevels({courseID: course.id}).models
|
|
.course-overview-row
|
|
.course-title.student-name
|
|
span= i18n(course.attributes, '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)
|
|
|
|
|
|
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 = i18n(level.attributes, 'name')
|
|
- context = _.merge(progress, { levelName: levelName, levelNumber: levelNumber, numStudents: view.students.length })
|
|
- link = null;
|
|
- labelText = levelNumber;
|
|
if level.isLadder()
|
|
- var course = view.state.get('selectedCourse');
|
|
- var courseInstance = course && view.classroom ? view.courseInstances.findWhere({ courseID: course.id, classroomID: view.classroom.id }) : null;
|
|
if courseInstance
|
|
- link = view.urls.courseArenaLadder({level: level, courseInstance: courseInstance});
|
|
- labelText = translate('teacher.view_arena_ladder');
|
|
else
|
|
- labelText = translate('courses.arena');
|
|
- dotClass = 'navy progress-dot-lg';
|
|
else if level.isProject()
|
|
- labelText = translate('teacher.project')
|
|
- dotClass += ' progress-dot-lg';
|
|
|
|
.progress-dot.level-progress-dot(class=dotClass, data-html='true', data-title=view.allStudentsLevelProgressDotTemplate(context))
|
|
if link
|
|
a(href=link)
|
|
+progressDotLabel(labelText)
|
|
else
|
|
+progressDotLabel(labelText)
|
|
|
|
|
|
mixin studentLevelProgressDot(progress, level, levelNumber)
|
|
//- TODO: Refactor with TeacherClassesView jade
|
|
- dotClass = progress.completed ? 'forest' : (progress.started ? 'gold' : '');
|
|
- levelName = i18n(level.attributes, 'name')
|
|
- context = _.merge(progress, { levelName: levelName, levelNumber: levelNumber, moment: moment })
|
|
- link = null;
|
|
- labelText = levelNumber;
|
|
if level.isLadder()
|
|
- var course = view.state.get('selectedCourse');
|
|
- 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
|
|
- labelText = translate('courses.arena');
|
|
- dotClass += ' progress-dot-lg';
|
|
else if level.isProject()
|
|
if progress.started
|
|
- link = view.urls.playDevLevel({level: level, session: progress.session, course: view.state.get('selectedCourse')});
|
|
- 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 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.class-code-blurb(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.class-code-blurb(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')
|
|
span.small
|
|
span(data-i18n='teacher.bulk_assign')
|
|
span :
|
|
select.bulk-course-select.form-control
|
|
each trimCourse in _.rest(view.sortedCourses)
|
|
- var course = view.courses.get(trimCourse._id)
|
|
option(value=course.id selected=(course===state.get('selectedCourse')))
|
|
= i18n(course.attributes, 'name')
|
|
button.btn.btn-primary-alt.assign-to-selected-students
|
|
span(data-i18n='teacher.assign_to_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#license-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.apply_license", data-user-id=student.id, data-event-action="Teachers Class Enrollment Enroll Student")
|