mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-13 09:11:22 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
c85a7230a6
22 changed files with 228 additions and 226 deletions
|
@ -95,9 +95,13 @@ module.exports = class Tracker extends CocoClass
|
|||
analytics.identify me.id, traits
|
||||
|
||||
trackPageView: (includeIntegrations=[]) ->
|
||||
includeMixpanel = (name) ->
|
||||
mixpanelIncludes = ['', 'schools', 'play', 'play/level/dungeons-of-kithgard']
|
||||
name in mixpanelIncludes or /courses|students|teachers/ig.test(name)
|
||||
|
||||
name = Backbone.history.getFragment()
|
||||
url = "/#{name}"
|
||||
console.log "Would track analytics pageview: #{url}" if debugAnalytics
|
||||
console.log "Would track analytics pageview: #{url} Mixpanel=#{includeMixpanel(name)}" if debugAnalytics
|
||||
@trackEventInternal 'Pageview', url: name unless me?.isAdmin() and @isProduction
|
||||
return unless @isProduction and not me.isAdmin()
|
||||
|
||||
|
@ -106,8 +110,7 @@ module.exports = class Tracker extends CocoClass
|
|||
ga? 'send', 'pageview', url
|
||||
|
||||
# Mixpanel
|
||||
mixpanelIncludes = ['', 'courses', 'courses/purchase', 'courses/teachers', 'courses/students', 'schools', 'teachers', 'teachers/freetrial', 'teachers/quote', 'play', 'play/level/dungeons-of-kithgard']
|
||||
mixpanel.track('page viewed', 'page name' : name, url : url) if name in mixpanelIncludes
|
||||
mixpanel.track('page viewed', 'page name' : name, url : url) if includeMixpanel(name)
|
||||
|
||||
if me.isTeacher() and @segmentLoaded
|
||||
options = {}
|
||||
|
|
|
@ -67,7 +67,7 @@ block content
|
|||
h5
|
||||
span.spr= classroom.get('name')
|
||||
span.spr (#{(classroom.get('aceConfig') || {}).language === 'javascript' ? 'JavaScript' : 'Python'})
|
||||
a(href="/courses/"+classroom.id, data-i18n="courses.view_class")
|
||||
a.view-class-btn(data-classroom-id=classroom.id, data-i18n="courses.view_class")
|
||||
|
||||
- var courseInstances = view.courseInstances.where({classroomID: classroom.id});
|
||||
for courseInstance in courseInstances
|
||||
|
@ -77,7 +77,7 @@ block content
|
|||
h6
|
||||
span.spr= course.get('name')
|
||||
small
|
||||
a(href="/courses/"+courseInstance.get('courseID')+'/'+courseInstance.id, data-i18n="courses.view_levels")
|
||||
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
|
||||
|
||||
|
@ -112,19 +112,19 @@ mixin course-instance-body(courseInstance, classroom)
|
|||
- var arenaLevel = stats.levels.arena;
|
||||
if arenaLevel
|
||||
- var arenaURL = "/play/ladder/"+arenaLevel.get('slug')+"/course/"+courseInstance.id;
|
||||
a.btn.btn-burgandy.btn-lg.m-b-1(href=arenaURL)
|
||||
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")
|
||||
span(data-i18n="courses.play_arena")
|
||||
else
|
||||
a.btn.btn-default.btn-lg.m-b-1(disabled=true, data-i18n="courses.course_complete")
|
||||
else if stats.levels.next != stats.levels.first
|
||||
- var next = stats.levels.next;
|
||||
- var levelURL = "/play/level/"+next.get('slug')+"?course="+courseInstance.get('courseID')+"&course-instance="+courseInstance.id;
|
||||
a.btn.btn-forest.btn-lg.m-b-1(href=levelURL)
|
||||
a.play-btn.btn.btn-forest.btn-lg.m-b-1(data-href=levelURL, data-level-slug=next.get('slug'), data-event-action="Students Continue Course")
|
||||
span(data-i18n="common.continue")
|
||||
else
|
||||
- var firstLevel = stats.levels.first;
|
||||
- var levelURL = "/play/level/"+firstLevel.get('slug')+"?course="+courseInstance.get('courseID')+"&course-instance="+courseInstance.id;
|
||||
a.btn.btn-navy.btn-lg.m-b-1(href=levelURL)
|
||||
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
|
||||
|
|
|
@ -244,7 +244,7 @@ mixin studentRow(student)
|
|||
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)
|
||||
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
|
||||
|
@ -294,7 +294,7 @@ mixin courseProgressTab
|
|||
span(data-i18n='TODO')
|
||||
| Assign Course
|
||||
else
|
||||
.enroll-student-button.btn.btn-md.btn-navy.pull-right(data-user-id=student.id)
|
||||
.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
|
||||
|
||||
|
@ -426,4 +426,4 @@ mixin enrollmentStatusTab
|
|||
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)
|
||||
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")
|
||||
|
|
|
@ -10,15 +10,15 @@ block content
|
|||
p(data-i18n='teacher.teacher_account_required')
|
||||
if me.isAnonymous()
|
||||
.login-button.btn.btn-lg.btn-primary(data-i18n='login.log_in')
|
||||
a.btn.btn-lg.btn-primary-alt(href="/teachers/signup" data-i18n='teacher.create_teacher_account')
|
||||
button.btn.btn-lg.btn-primary-alt.create-teacher-btn(data-event-action="Teachers Classes Create Teacher Account", data-i18n='teacher.create_teacher_account')
|
||||
else
|
||||
a.btn.btn-lg.btn-primary(href="/teachers/update-account" data-i18n="teachers_quote.convert_account_title")
|
||||
button.btn.btn-lg.btn-primary.update-teacher-btn(data-event-action="Teachers Classes Convert Teacher Account", data-i18n="teachers_quote.convert_account_title")
|
||||
button#logout-button.btn.btn-lg.btn-primary-alt(data-i18n="login.log_out")
|
||||
|
||||
|
||||
.teacher-account-blurb.text-center.col-xs-6.col-xs-offset-3.m-y-3
|
||||
h5(data-i18n='teacher.what_is_a_teacher_account')
|
||||
p(data-i18n='teacher.teacher_account_explanation')
|
||||
|
||||
|
||||
else
|
||||
if !me.isTeacher()
|
||||
.alert.alert-danger.text-center
|
||||
|
@ -27,30 +27,30 @@ block content
|
|||
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
|
||||
|
||||
| Please convert your account to ensure you retain access to your classrooms.
|
||||
button.btn.btn-primary.btn-lg.update-teacher-btn(data-event-action="Teachers Classes Convert Teacher Account Temp") Upgrade to teacher account
|
||||
|
||||
.container
|
||||
h3(data-i18n='teacher.current_classes')
|
||||
|
||||
|
||||
.classes.container
|
||||
// Loop each class
|
||||
each classroom in view.classrooms.models
|
||||
unless classroom.get('archived')
|
||||
+classRow(classroom)
|
||||
|
||||
|
||||
+createClassButton
|
||||
|
||||
|
||||
- var archivedClassrooms = view.classrooms.where({archived: true});
|
||||
if _.size(archivedClassrooms)
|
||||
.container
|
||||
h3(data-i18n='teacher.archived_classes')
|
||||
p(data-i18n='teacher.archived_classes_blurb')
|
||||
|
||||
|
||||
.classes.container
|
||||
each classroom in archivedClassrooms
|
||||
+archivedClassRow(classroom)
|
||||
|
||||
|
||||
mixin classRow(classroom)
|
||||
.class.row
|
||||
.col-xs-6
|
||||
|
@ -67,9 +67,9 @@ mixin classRow(classroom)
|
|||
span
|
||||
= classroom.get('members').length
|
||||
.class-links
|
||||
a.text-h6(data-i18n='teacher.view_class' href=('/teachers/classes/' + classroom.id))
|
||||
a.edit-classroom.text-h6(data-i18n='teacher.edit_class_settings' data-classroom-id=classroom.id)
|
||||
a.archive-classroom.text-h6(data-i18n='teacher.archive_class' data-classroom-id=classroom.id)
|
||||
a.view-class-btn.text-h6(data-i18n='teacher.view_class' data-classroom-id=classroom.id data-event-action="Teachers Classes View Class Link")
|
||||
a.edit-classroom.text-h6(data-i18n='teacher.edit_class_settings' data-classroom-id=classroom.id data-event-action="Teachers Classes Edit Class Started")
|
||||
a.archive-classroom.text-h6(data-i18n='teacher.archive_class' data-classroom-id=classroom.id data-event-action="Teachers Classes Archive Class")
|
||||
|
||||
.progress-col.col-xs-5
|
||||
if classroom.get('members').length == 0
|
||||
|
@ -80,7 +80,7 @@ mixin classRow(classroom)
|
|||
if view.courseInstances.findWhere({ classroomID: classroom.id, courseID: course.id })
|
||||
+progressDot(classroom, course, index)
|
||||
.view-class-arrow.col-xs-1
|
||||
a.view-class-arrow-inner.glyphicon.glyphicon-chevron-right(data-classroom-id=classroom.id, href=('/teachers/classes/' + classroom.id))
|
||||
a.view-class-arrow-inner.glyphicon.glyphicon-chevron-right.view-class-btn(data-classroom-id=classroom.id data-event-action="Teachers Classes View Class Chevron")
|
||||
|
||||
|
||||
mixin addStudentsButton(classroom)
|
||||
|
@ -91,7 +91,7 @@ mixin addStudentsButton(classroom)
|
|||
a.add-students-btn.btn.btn-lg.btn-primary(data-classroom-id=classroom.id )
|
||||
span(data-i18n='teacher.add_students')
|
||||
| Add Students
|
||||
|
||||
|
||||
mixin createClassButton
|
||||
.create-class
|
||||
.text-center
|
||||
|
@ -110,7 +110,7 @@ mixin progressDot(classroom, course, index)
|
|||
- complete = courseInstance.numCompleted
|
||||
- started = courseInstance.started
|
||||
- dotClass = complete === total ? 'forest' : started ? 'gold' : '';
|
||||
- var progressDotContext = {total: total, complete: complete};
|
||||
- var progressDotContext = {total: total, complete: complete};
|
||||
.progress-dot(class=dotClass, data-title=view.progressDotTemplate(progressDotContext))
|
||||
+progressDotLabel(index)
|
||||
|
||||
|
|
|
@ -86,10 +86,10 @@ mixin course-info(course)
|
|||
if view.guideLinks[course.id]
|
||||
//- a.btn.btn-primary(href=view.guideLinks[course.id] class=(me.isTeacher() ? '': 'disabled'))
|
||||
//- span(data-i18n="courses.print_guide")
|
||||
a.btn.btn-primary(href=view.guideLinks[course.id].python class=(me.isTeacher() ? '': 'disabled'))
|
||||
a.guide-btn.btn.btn-primary(href=view.guideLinks[course.id].python data-course-id=course.id data-course-name=course.get('name') data-event-action="Classes Guides Guide Python" class=(me.isTeacher() ? '': 'disabled'))
|
||||
span(data-i18n="courses.view_guide_online")
|
||||
| — Python
|
||||
a.btn.btn-primary(href=view.guideLinks[course.id].javascript class=(me.isTeacher() ? '': 'disabled'))
|
||||
a.guide-btn.btn.btn-primary(href=view.guideLinks[course.id].javascript data-course-id=course.id data-course-name=course.get('name') data-event-action="Classes Guides Guide JavaScript" class=(me.isTeacher() ? '': 'disabled'))
|
||||
span(data-i18n="courses.view_guide_online")
|
||||
| — JavaScript
|
||||
else
|
||||
|
|
|
@ -5,36 +5,36 @@ mixin box
|
|||
if me.isAnonymous() == true
|
||||
h6#classroom-edition-header(data-i18n="new_home.classroom_edition")
|
||||
div
|
||||
button.teacher-btn.btn.btn-primary.btn-lg.btn-block(data-i18n="new_home.im_a_teacher")
|
||||
a.teacher-btn.btn.btn-primary.btn-lg.btn-block(data-event-action="Homepage Click Teacher Button CTA", data-i18n="new_home.im_a_teacher")
|
||||
div
|
||||
a.btn.btn-forest.btn-lg.btn-block(href="/courses", data-i18n="new_home.im_a_student")
|
||||
a.student-btn.btn.btn-forest.btn-lg.btn-block(href="/courses", data-event-action="Homepage Click Student Button CTA", data-i18n="new_home.im_a_student")
|
||||
h6#learn-to-code-header(data-i18n="new_home.learn_to_code")
|
||||
a.btn.btn-gold.btn-lg.btn-block.play-btn(href=view.playURL, data-i18n="new_home.play_now")
|
||||
a.btn.btn-gold.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage Play Now CTA", data-i18n="new_home.play_now")
|
||||
|
||||
else
|
||||
h6#classroom-edition-header(data-i18n="new_home.logged_in_as")
|
||||
p.small #{me.get("email")}
|
||||
if me.isTeacher()
|
||||
div
|
||||
button.teacher-btn.btn.btn-forest.btn-lg.btn-block(data-i18n="new_home.goto_classes")
|
||||
button.teacher-btn.btn.btn-forest.btn-lg.btn-block(data-event-action="Homepage Click My Classes CTA", data-i18n="new_home.goto_classes")
|
||||
div
|
||||
if view.isTeacherWithDemo
|
||||
h6(data-i18n="new_home.check_out_wiki")
|
||||
a.btn.btn-primary.btn-lg.btn-block(href="https://sites.google.com/a/codecombat.com/teacher-guides/course-guides", data-i18n="nav.educator_wiki")
|
||||
button.wiki-btn.btn.btn-primary.btn-lg.btn-block(data-event-action="Homepage Click Educator Wiki CTA", data-i18n="nav.educator_wiki")
|
||||
else
|
||||
h6(data-i18n="new_home.want_coco")
|
||||
a.btn.btn-primary.btn-lg.btn-block(href=view.demoRequestURL, data-i18n="new_home.get_started")
|
||||
button.btn.btn-primary.btn-lg.request-demo(data-event-action="Homepage Request Demo CTA", data-i18n="new_home.request_demo")
|
||||
|
||||
else if me.justPlaysCourses()
|
||||
div
|
||||
a.btn.btn-forest.btn-lg.btn-block(href=view.playURL, data-i18n="courses.continue_playing")
|
||||
a.btn.btn-forest.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage Classroom Continue Playing CTA", data-i18n="courses.continue_playing")
|
||||
div
|
||||
a.btn.btn-primary.btn-lg.btn-block.play-btn(href=view.playURL, data-i18n="new_home.view_progress")
|
||||
a.btn.btn-primary.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage View Progress CTA", data-i18n="new_home.view_progress")
|
||||
else
|
||||
div
|
||||
a.btn.btn-forest.btn-lg.btn-block.play-btn(href=view.playURL, data-i18n="courses.continue_playing")
|
||||
a.btn.btn-forest.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage Campaign Continue Playing CTA", data-i18n="courses.continue_playing")
|
||||
div
|
||||
a.btn.btn-primary.btn-lg.btn-block(href="/user/#{me.getSlugOrID()}", data-i18n="new_home.view_profile")
|
||||
a.btn.btn-primary.btn-lg.btn-block.profile-btn(href=view.playURL, data-event-action="Homepage View Profile CTA", data-i18n="new_home.view_profile")
|
||||
|
||||
|
||||
p.small
|
||||
|
@ -213,11 +213,11 @@ block content
|
|||
if view.isTeacherWithDemo
|
||||
h4(data-i18n="new_home.get_started_subtitle")
|
||||
div
|
||||
a.btn.btn-primary.btn-lg(href="/teachers/classes", data-i18n="new_home.setup_a_class")
|
||||
button.btn.btn-primary.btn-lg.setup-class-btn(data-event-action="Homepage Setup Class", data-i18n="new_home.setup_a_class")
|
||||
else
|
||||
h4(data-i18n="new_home.request_demo_subtitle")
|
||||
div
|
||||
a.btn.btn-primary.btn-lg(href=view.demoRequestURL, data-i18n="new_home.request_demo")
|
||||
button.btn.btn-primary.btn-lg.request-demo(data-event-action="Homepage Request Demo", data-i18n="new_home.request_demo")
|
||||
if me.isAnonymous()
|
||||
.have-an-account
|
||||
span.spr(data-i18n="new_home.have_an_account")
|
||||
|
@ -306,10 +306,10 @@ block content
|
|||
h3(data-i18n="new_home.run_class")
|
||||
if view.isTeacherWithDemo
|
||||
div
|
||||
a.btn.btn-primary.btn-lg(href="/teachers/classes", data-i18n="new_home.setup_a_class")
|
||||
button.btn.btn-primary.btn-lg.setup-class-btn(data-event-action="Homepage Setup Class Page Bottom", data-i18n="new_home.setup_a_class")
|
||||
else
|
||||
div
|
||||
a.btn.btn-primary.btn-lg(href=view.demoRequestURL, data-i18n="new_home.request_demo")
|
||||
button.btn.btn-primary.btn-lg.request-demo(data-event-action="Homepage Request Demo Page Bottom", data-i18n="new_home.request_demo")
|
||||
if me.isAnonymous()
|
||||
.have-an-account
|
||||
span.spr(data-i18n="new_home.have_an_account")
|
||||
|
|
|
@ -18,14 +18,17 @@ module.exports = class NewHomeView extends RootView
|
|||
events:
|
||||
'click .play-btn': 'onClickPlayButton'
|
||||
'change #school-level-dropdown': 'onChangeSchoolLevelDropdown'
|
||||
'click .student-btn': 'onClickStudentButton'
|
||||
'click .teacher-btn': 'onClickTeacherButton'
|
||||
'click #learn-more-link': 'onClickLearnMoreLink'
|
||||
'click .screen-thumbnail': 'onClickScreenThumbnail'
|
||||
'click #carousel-left': 'onLeftPressed'
|
||||
'click #carousel-right': 'onRightPressed'
|
||||
'click .request-demo': 'onClickRequestDemo'
|
||||
'click .join-class': 'onClickJoinClass'
|
||||
'click .logout-btn': 'logoutAccount'
|
||||
'click .profile-btn': 'onClickViewProfile'
|
||||
'click .setup-class-btn': 'onClickSetupClass'
|
||||
'click .wiki-btn': 'onClickWikiButton'
|
||||
|
||||
shortcuts:
|
||||
'right': 'onRightPressed'
|
||||
|
@ -36,7 +39,6 @@ module.exports = class NewHomeView extends RootView
|
|||
@courses = new CocoCollection [], {url: "/db/course", model: Course}
|
||||
@supermodel.loadCollection(@courses, 'courses')
|
||||
|
||||
window.tracker?.trackEvent 'Homepage Loaded', category: 'Homepage'
|
||||
if me.isTeacher()
|
||||
@trialRequests = new TrialRequests()
|
||||
@trialRequests.fetchOwn()
|
||||
|
@ -51,43 +53,52 @@ module.exports = class NewHomeView extends RootView
|
|||
else if me.justPlaysCourses()
|
||||
# Save players who might be in a classroom from getting into the campaign
|
||||
@playURL = '/courses'
|
||||
@alternatePlayURL = '/play'
|
||||
@alternatePlayText = 'home.play_campaign_version'
|
||||
else
|
||||
@playURL = '/play'
|
||||
|
||||
onLoaded: ->
|
||||
@trialRequest = @trialRequests.first() if @trialRequests?.size()
|
||||
@isTeacherWithDemo = @trialRequest and @trialRequest.get('status') in ['approved', 'submitted']
|
||||
@demoRequestURL = if me.isTeacher() then '/teachers/update-account' else '/teachers/demo'
|
||||
super()
|
||||
|
||||
onClickLearnMoreLink: ->
|
||||
window.tracker?.trackEvent 'Homepage Click Learn More', category: 'Homepage', ['Mixpanel']
|
||||
@scrollToLink('#classroom-in-box-container')
|
||||
|
||||
onClickPlayButton: (e) ->
|
||||
@playSound 'menu-button-click'
|
||||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
window.tracker?.trackEvent 'Homepage Click Play', category: 'Homepage'
|
||||
application.router.navigate @playURL, trigger: true
|
||||
#window.open @playURL, '_blank'
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', ['Mixpanel']
|
||||
|
||||
onClickRequestDemo: (e) ->
|
||||
@playSound 'menu-button-click'
|
||||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
window.tracker?.trackEvent 'Homepage Submit Jumbo Form', category: 'Homepage'
|
||||
obj = storage.load('request-quote-form')
|
||||
obj ?= {}
|
||||
obj.role = @$('#request-form-role').val()
|
||||
obj.numStudents = @$('#request-form-range').val()
|
||||
storage.save('request-quote-form', obj)
|
||||
application.router.navigate "/teachers/demo", trigger: true
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', ['Mixpanel']
|
||||
if me.isTeacher()
|
||||
application.router.navigate '/teachers/update-account', trigger: true
|
||||
else
|
||||
application.router.navigate '/teachers/demo', trigger: true
|
||||
|
||||
onClickJoinClass: (e) ->
|
||||
@playSound 'menu-button-click'
|
||||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
window.tracker?.trackEvent 'Homepage Click Join Class', category: 'Homepage'
|
||||
application.router.navigate "/courses", trigger: true
|
||||
onClickSetupClass: (e) ->
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', ['Mixpanel']
|
||||
application.router.navigate("/teachers/classes", { trigger: true })
|
||||
|
||||
onClickStudentButton: (e) ->
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', ['Mixpanel']
|
||||
|
||||
onClickTeacherButton: (e) ->
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', ['Mixpanel']
|
||||
if me.isTeacher()
|
||||
application.router.navigate('/teachers', { trigger: true })
|
||||
else
|
||||
@scrollToLink('.request-demo-row', 600)
|
||||
|
||||
onClickViewProfile: (e) ->
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', ['Mixpanel']
|
||||
application.router.navigate("/user/#{me.getSlugOrID()}", { trigger: true })
|
||||
|
||||
onClickWikiButton: (e) ->
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', ['Mixpanel']
|
||||
window.location.href = 'https://sites.google.com/a/codecombat.com/teacher-guides/course-guides'
|
||||
|
||||
afterRender: ->
|
||||
@onChangeSchoolLevelDropdown()
|
||||
|
@ -125,18 +136,6 @@ module.exports = class NewHomeView extends RootView
|
|||
isNewPlayer: ->
|
||||
not me.get('stats')?.gamesCompleted and not me.get('heroConfig')
|
||||
|
||||
onClickLearnMoreLink: ->
|
||||
window.tracker?.trackEvent 'Homepage Click Learn More', category: 'Homepage'
|
||||
@scrollToLink('#classroom-in-box-container')
|
||||
|
||||
onClickTeacherButton: ->
|
||||
if me.isTeacher()
|
||||
window.tracker?.trackEvent 'Homepage Click Teacher Button (logged in)', category: 'Homepage'
|
||||
application.router.navigate('/teachers', { trigger: true })
|
||||
else
|
||||
window.tracker?.trackEvent 'Homepage Click Teacher Button', category: 'Homepage'
|
||||
@scrollToLink('.request-demo-row', 600)
|
||||
|
||||
onRightPressed: (event) ->
|
||||
# Special handling, otherwise after you click the control, keyboard presses move the slide twice
|
||||
return if event.type is 'keydown' and $(document.activeElement).is('.carousel-control')
|
||||
|
|
|
@ -14,10 +14,6 @@ module.exports = class ClassroomSettingsModal extends ModalView
|
|||
|
||||
initialize: (options={}) ->
|
||||
@classroom = options.classroom or new Classroom()
|
||||
if @classroom.isNew()
|
||||
application.tracker?.trackEvent 'Create new class', category: 'Courses'
|
||||
else
|
||||
application.tracker?.trackEvent 'Classroom started edit settings', category: 'Courses', classroomID: @classroom.id
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
@ -53,3 +49,5 @@ module.exports = class ClassroomSettingsModal extends ModalView
|
|||
button.text(@oldButtonText).attr('disabled', false)
|
||||
errors.showNotyNetworkError(jqxhr)
|
||||
@listenToOnce @classroom, 'sync', @hide
|
||||
window.tracker?.trackEvent "Teachers Edit Class Saved", category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
|
||||
|
|
|
@ -57,8 +57,8 @@ module.exports = class ClassroomView extends RootView
|
|||
@levels = new Levels()
|
||||
@levels.fetchForClassroom(classroomID, {data: {project: 'name,slug,original'}})
|
||||
@levels.on 'add', (model) -> @_byId[model.get('original')] = model # so you can 'get' them
|
||||
|
||||
@supermodel.trackCollection(@levels)
|
||||
window.tracker?.trackEvent 'Students Class Loaded', category: 'Students', classroomID: classroomID, ['Mixpanel']
|
||||
|
||||
onCourseInstancesSync: ->
|
||||
@sessions = new CocoCollection([], { model: LevelSession })
|
||||
|
|
|
@ -74,6 +74,10 @@ module.exports = class CourseDetailsView extends RootView
|
|||
))
|
||||
))
|
||||
|
||||
initialize: (options) ->
|
||||
window.tracker?.trackEvent 'Students Class Course Loaded', category: 'Students', ['Mixpanel']
|
||||
super(options)
|
||||
|
||||
buildSessionStats: ->
|
||||
return if @destroyed
|
||||
|
||||
|
@ -125,6 +129,7 @@ module.exports = class CourseDetailsView extends RootView
|
|||
levelSlug = $(e.target).closest('.btn-play-level').data('level-slug')
|
||||
levelID = $(e.target).closest('.btn-play-level').data('level-id')
|
||||
level = @levels.findWhere({original: levelID})
|
||||
window.tracker?.trackEvent 'Students Class Course Play Level', category: 'Students', courseID: @courseID, courseInstanceID: @courseInstanceID, levelSlug: levelSlug, ['Mixpanel']
|
||||
if level.get('type') is 'course-ladder'
|
||||
viewClass = 'views/ladder/LadderView'
|
||||
viewArgs = [{supermodel: @supermodel}, levelSlug]
|
||||
|
|
|
@ -29,11 +29,14 @@ module.exports = class CoursesView extends RootView
|
|||
'click .change-hero-btn': 'onClickChangeHeroButton'
|
||||
'click #join-class-btn': 'onClickJoinClassButton'
|
||||
'submit #join-class-form': 'onSubmitJoinClassForm'
|
||||
'click #change-language-link': 'onClickChangeLanguageLink'
|
||||
'click .play-btn': 'onClickPlay'
|
||||
'click .view-class-btn': 'onClickViewClass'
|
||||
'click .view-levels-btn': 'onClickViewLevels'
|
||||
|
||||
getTitle: -> return $.i18n.t('teacher.students')
|
||||
|
||||
initialize: ->
|
||||
@classCodeQueryVar = utils.getQueryVariable('_cc', false)
|
||||
@courseInstances = new CocoCollection([], { url: "/db/user/#{me.id}/course_instances", model: CourseInstance})
|
||||
@courseInstances.comparator = (ci) -> return ci.get('classroomID') + ci.get('courseID')
|
||||
@listenToOnce @courseInstances, 'sync', @onCourseInstancesLoaded
|
||||
|
@ -55,6 +58,7 @@ module.exports = class CoursesView extends RootView
|
|||
@supermodel.loadModel(@hero, 'hero')
|
||||
@listenTo @hero, 'all', ->
|
||||
@render()
|
||||
window.tracker?.trackEvent 'Students Loaded', category: 'Students', ['Mixpanel']
|
||||
|
||||
onCourseInstancesLoaded: ->
|
||||
map = {}
|
||||
|
@ -76,20 +80,22 @@ module.exports = class CoursesView extends RootView
|
|||
|
||||
onLoaded: ->
|
||||
super()
|
||||
if utils.getQueryVariable('_cc', false) and not me.isAnonymous()
|
||||
if @classCodeQueryVar and not me.isAnonymous()
|
||||
window.tracker?.trackEvent 'Students Join Class Link', category: 'Students', classCode: @classCodeQueryVar, ['Mixpanel']
|
||||
@joinClass()
|
||||
|
||||
onClickLogInButton: ->
|
||||
modal = new AuthModal()
|
||||
@openModalView(modal)
|
||||
application.tracker?.trackEvent 'Started Student Login', category: 'Courses'
|
||||
window.tracker?.trackEvent 'Students Login Started', category: 'Students', ['Mixpanel']
|
||||
|
||||
openSignUpModal: ->
|
||||
window.tracker?.trackEvent 'Students Signup Started', category: 'Students', ['Mixpanel']
|
||||
modal = new CreateAccountModal({ initialValues: { classCode: utils.getQueryVariable('_cc', "") } })
|
||||
@openModalView(modal)
|
||||
application.tracker?.trackEvent 'Started Student Signup', category: 'Courses'
|
||||
|
||||
onClickChangeHeroButton: ->
|
||||
window.tracker?.trackEvent 'Students Change Hero Started', category: 'Students', ['Mixpanel']
|
||||
modal = new HeroSelectModal({ currentHeroID: @hero.id })
|
||||
@openModalView(modal)
|
||||
@listenTo modal, 'hero-select:success', (newHero) =>
|
||||
|
@ -101,16 +107,20 @@ module.exports = class CoursesView extends RootView
|
|||
|
||||
onSubmitJoinClassForm: (e) ->
|
||||
e.preventDefault()
|
||||
classCode = @$('#class-code-input').val() or @classCodeQueryVar
|
||||
window.tracker?.trackEvent 'Students Join Class With Code', category: 'Students', classCode: classCode, ['Mixpanel']
|
||||
@joinClass()
|
||||
|
||||
onClickJoinClassButton: (e) ->
|
||||
classCode = @$('#class-code-input').val() or @classCodeQueryVar
|
||||
window.tracker?.trackEvent 'Students Join Class With Code', category: 'Students', classCode: classCode, ['Mixpanel']
|
||||
@joinClass()
|
||||
|
||||
joinClass: ->
|
||||
return if @state
|
||||
@state = 'enrolling'
|
||||
@errorMessage = null
|
||||
@classCode = @$('#class-code-input').val() or utils.getQueryVariable('_cc', false)
|
||||
@classCode = @$('#class-code-input').val() or @classCodeQueryVar
|
||||
if not @classCode
|
||||
@state = null
|
||||
@errorMessage = 'Please enter a code.'
|
||||
|
@ -133,7 +143,6 @@ module.exports = class CoursesView extends RootView
|
|||
|
||||
onJoinClassroomError: (classroom, jqxhr, options) ->
|
||||
@state = null
|
||||
application.tracker?.trackEvent 'Failed to join classroom with code', category: 'Courses', status: jqxhr.status
|
||||
if jqxhr.status is 422
|
||||
@errorMessage = 'Please enter a code.'
|
||||
else if jqxhr.status is 404
|
||||
|
@ -161,9 +170,19 @@ module.exports = class CoursesView extends RootView
|
|||
# TODO: Smoother system for joining a classroom and course instances, without requiring page reload,
|
||||
# and showing which class was just joined.
|
||||
document.location.search = '' # Using document.location.reload() causes an infinite loop of reloading
|
||||
|
||||
onClickChangeLanguageLink: ->
|
||||
application.tracker?.trackEvent 'Student clicked change language', category: 'Courses'
|
||||
modal = new ChangeCourseLanguageModal()
|
||||
@openModalView(modal)
|
||||
modal.once 'hidden', @render, @
|
||||
|
||||
onClickPlay: (e) ->
|
||||
levelSlug = $(e.currentTarget).data('level-slug')
|
||||
window.tracker?.trackEvent $(e.currentTarget).data('event-action'), category: 'Students', levelSlug: levelSlug, ['Mixpanel']
|
||||
application.router.navigate($(e.currentTarget).data('href'), { trigger: true })
|
||||
|
||||
onClickViewClass: (e) ->
|
||||
classroomID = $(e.target).data('classroom-id')
|
||||
window.tracker?.trackEvent 'Students View Class', category: 'Students', classroomID: classroomID, ['Mixpanel']
|
||||
application.router.navigate("/courses/#{classroomID}", { trigger: true })
|
||||
|
||||
onClickViewLevels: (e) ->
|
||||
courseID = $(e.target).data('course-id')
|
||||
courseInstanceID = $(e.target).data('courseinstance-id')
|
||||
window.tracker?.trackEvent 'Students View Levels', category: 'Students', courseID: courseID, courseInstanceID: courseInstanceID, ['Mixpanel']
|
||||
application.router.navigate("/courses/#{courseID}/#{courseInstanceID}", { trigger: true })
|
||||
|
|
|
@ -21,7 +21,7 @@ module.exports = class EnrollmentsView extends RootView
|
|||
|
||||
getTitle: -> return $.i18n.t('teacher.enrollments')
|
||||
|
||||
initialize: ->
|
||||
initialize: (options) ->
|
||||
@state = new State({
|
||||
totalEnrolled: 0
|
||||
totalNotEnrolled: 0
|
||||
|
@ -34,6 +34,8 @@ module.exports = class EnrollmentsView extends RootView
|
|||
'pending': []
|
||||
}
|
||||
})
|
||||
window.tracker?.trackEvent 'Classes Licenses Loaded', category: 'Teachers', ['Mixpanel']
|
||||
super(options)
|
||||
|
||||
@courses = new Courses()
|
||||
@supermodel.trackRequest @courses.fetch({data: { project: 'free' }})
|
||||
|
@ -58,31 +60,31 @@ module.exports = class EnrollmentsView extends RootView
|
|||
@calculateEnrollmentStats()
|
||||
@state.set('totalCourses', @courses.size())
|
||||
super()
|
||||
|
||||
|
||||
updatePrepaidGroups: ->
|
||||
@state.set('prepaidGroups', @prepaids.groupBy((p) -> p.status()))
|
||||
|
||||
calculateEnrollmentStats: ->
|
||||
@removeDeletedStudents()
|
||||
|
||||
|
||||
# sort users into enrolled, not enrolled
|
||||
groups = @members.groupBy (m) -> m.isEnrolled()
|
||||
enrolledUsers = new Users(groups.true)
|
||||
@notEnrolledUsers = new Users(groups.false)
|
||||
|
||||
map = {}
|
||||
|
||||
map = {}
|
||||
|
||||
for classroom in @classrooms.models
|
||||
map[classroom.id] = _.countBy(classroom.get('members'), (userID) -> enrolledUsers.get(userID)?).false
|
||||
|
||||
|
||||
@state.set({
|
||||
totalEnrolled: enrolledUsers.size()
|
||||
totalNotEnrolled: @notEnrolledUsers.size()
|
||||
classroomNotEnrolledMap: map
|
||||
})
|
||||
|
||||
|
||||
true
|
||||
|
||||
|
||||
removeDeletedStudents: (e) ->
|
||||
for classroom in @classrooms.models
|
||||
_.remove(classroom.get('members'), (memberID) =>
|
||||
|
@ -94,8 +96,9 @@ module.exports = class EnrollmentsView extends RootView
|
|||
@openModalView(new HowToEnrollModal())
|
||||
|
||||
onClickContactUsButton: ->
|
||||
window.tracker?.trackEvent 'Classes Licenses Contact Us', category: 'Teachers', enrollmentsNeeded: @state.get('numberOfStudents'), ['Mixpanel']
|
||||
@openModalView(new TeachersContactModal({ enrollmentsNeeded: @state.get('numberOfStudents') }))
|
||||
|
||||
|
||||
onInputStudentsInput: ->
|
||||
input = @$('#students-input').val()
|
||||
if input isnt "" and (parseFloat(input) isnt parseInt(input) or _.isNaN parseInt(input))
|
||||
|
@ -106,6 +109,7 @@ module.exports = class EnrollmentsView extends RootView
|
|||
numberOfStudentsIsValid: -> 0 < @get('numberOfStudents') < 100000
|
||||
|
||||
onClickEnrollStudentsButton: ->
|
||||
window.tracker?.trackEvent 'Classes Licenses Enroll Students', category: 'Teachers', ['Mixpanel']
|
||||
modal = new ActivateLicensesModal({ selectedUsers: @notEnrolledUsers, users: @members })
|
||||
@openModalView(modal)
|
||||
modal.once 'hidden', =>
|
||||
|
|
|
@ -2,4 +2,7 @@ RootView = require 'views/core/RootView'
|
|||
|
||||
module.exports = class RestrictedToStudentsView extends RootView
|
||||
id: 'restricted-to-students-view'
|
||||
template: require 'templates/courses/restricted-to-students-view'
|
||||
template: require 'templates/courses/restricted-to-students-view'
|
||||
|
||||
initialize: ->
|
||||
window.tracker?.trackEvent 'Restricted To Students Loaded', category: 'Students', ['Mixpanel']
|
||||
|
|
|
@ -120,6 +120,7 @@ module.exports = class TeacherClassView extends RootView
|
|||
@supermodel.trackRequest @levels.fetchForClassroom(classroomID, {data: {project: 'original,concepts'}})
|
||||
|
||||
@attachMediatorEvents()
|
||||
window.tracker?.trackEvent 'Teachers Class Loaded', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
|
||||
attachMediatorEvents: () ->
|
||||
# Model/Collection events
|
||||
|
@ -211,31 +212,35 @@ module.exports = class TeacherClassView extends RootView
|
|||
window.location.hash = hash
|
||||
|
||||
onClickCopyCodeButton: ->
|
||||
window.tracker?.trackEvent 'Teachers Class Copy Class Code', category: 'Teachers', classroomID: @classroom.id, classCode: @state.get('classCode'), ['Mixpanel']
|
||||
@$('#join-code-input').val(@state.get('classCode')).select()
|
||||
@tryCopy()
|
||||
|
||||
onClickCopyURLButton: ->
|
||||
window.tracker?.trackEvent 'Teachers Class Copy Class URL', category: 'Teachers', classroomID: @classroom.id, url: @state.get('joinURL'), ['Mixpanel']
|
||||
@$('#join-url-input').val(@state.get('joinURL')).select()
|
||||
@tryCopy()
|
||||
|
||||
tryCopy: ->
|
||||
try
|
||||
document.execCommand('copy')
|
||||
application.tracker?.trackEvent 'Classroom copy URL', category: 'Courses', classroomID: @classroom.id, url: @state.joinURL
|
||||
catch err
|
||||
message = 'Oops, unable to copy'
|
||||
noty text: message, layout: 'topCenter', type: 'error', killer: false
|
||||
|
||||
onClickUnarchive: ->
|
||||
window.tracker?.trackEvent 'Teachers Class Unarchive', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
@classroom.save { archived: false }
|
||||
|
||||
onClickEditClassroom: (e) ->
|
||||
window.tracker?.trackEvent 'Teachers Class Edit Class Started', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
classroom = @classroom
|
||||
modal = new ClassroomSettingsModal({ classroom: classroom })
|
||||
@openModalView(modal)
|
||||
@listenToOnce modal, 'hide', @render
|
||||
|
||||
onClickEditStudentLink: (e) ->
|
||||
window.tracker?.trackEvent 'Teachers Class Students Edit', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
user = @students.get($(e.currentTarget).data('student-id'))
|
||||
modal = new EditStudentModal({ user, @classroom })
|
||||
@openModalView(modal)
|
||||
|
@ -252,9 +257,10 @@ module.exports = class TeacherClassView extends RootView
|
|||
|
||||
onStudentRemoved: (e) ->
|
||||
@students.remove(e.user)
|
||||
application.tracker?.trackEvent 'Classroom removed student', category: 'Courses', classroomID: @classroom.id, userID: e.user.id
|
||||
window.tracker?.trackEvent 'Teachers Class Students Removed', category: 'Teachers', classroomID: @classroom.id, userID: e.user.id, ['Mixpanel']
|
||||
|
||||
onClickAddStudents: (e) =>
|
||||
window.tracker?.trackEvent 'Teachers Class Add Students', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
modal = new InviteToClassroomModal({ classroom: @classroom })
|
||||
@openModalView(modal)
|
||||
@listenToOnce modal, 'hide', @render
|
||||
|
@ -294,14 +300,14 @@ module.exports = class TeacherClassView extends RootView
|
|||
user = @students.get(userID)
|
||||
selectedUsers = new Users([user])
|
||||
@enrollStudents(selectedUsers)
|
||||
|
||||
window.tracker?.trackEvent $(e.currentTarget).data('event-action'), category: 'Teachers', classroomID: @classroom.id, userID: userID, ['Mixpanel']
|
||||
|
||||
onClickBulkEnroll: ->
|
||||
courseID = @$('.bulk-course-select').val()
|
||||
courseInstance = @courseInstances.findWhere({ courseID, classroomID: @classroom.id })
|
||||
userIDs = @getSelectedStudentIDs().toArray()
|
||||
selectedUsers = new Users(@students.get(userID) for userID in userIDs)
|
||||
@enrollStudents(selectedUsers)
|
||||
|
||||
window.tracker?.trackEvent 'Teachers Class Students Enroll Selected', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
|
||||
enrollStudents: (selectedUsers) ->
|
||||
modal = new ActivateLicensesModal { @classroom, selectedUsers, users: @students }
|
||||
@openModalView(modal)
|
||||
|
@ -311,10 +317,10 @@ module.exports = class TeacherClassView extends RootView
|
|||
if user
|
||||
user.set(newUser.attributes)
|
||||
null
|
||||
application.tracker?.trackEvent 'Classroom started enroll students', category: 'Courses'
|
||||
|
||||
onClickExportStudentProgress: ->
|
||||
# TODO: Does not yield .csv download on Safari, and instead opens a new tab with the .csv contents
|
||||
window.tracker?.trackEvent 'Teachers Class Export CSV', category: 'Teachers', classroomID: @classroom.id, ['Mixpanel']
|
||||
csvContent = "data:text/csv;charset=utf-8,Username, Email, Playtime, Concepts\n"
|
||||
for student in @students.models
|
||||
concepts = []
|
||||
|
@ -336,15 +342,14 @@ module.exports = class TeacherClassView extends RootView
|
|||
encodedUri = encodeURI(csvContent)
|
||||
window.open(encodedUri)
|
||||
|
||||
|
||||
onClickAssignStudentButton: (e) ->
|
||||
userID = $(e.currentTarget).data('user-id')
|
||||
user = @students.get(userID)
|
||||
members = [userID]
|
||||
courseID = $(e.currentTarget).data('course-id')
|
||||
|
||||
@assignCourse courseID, members
|
||||
|
||||
window.tracker?.trackEvent 'Teachers Class Students Assign Selected', category: 'Teachers', classroomID: @classroom.id, courseID: courseID, userID: userID, ['Mixpanel']
|
||||
|
||||
onClickBulkAssign: ->
|
||||
courseID = @$('.bulk-course-select').val()
|
||||
selectedIDs = @getSelectedStudentIDs()
|
||||
|
@ -352,16 +357,13 @@ module.exports = class TeacherClassView extends RootView
|
|||
user = @students.get(userID)
|
||||
user.isEnrolled()
|
||||
).toArray()
|
||||
|
||||
assigningToUnenrolled = _.any selectedIDs, (userID) =>
|
||||
not @students.get(userID).isEnrolled()
|
||||
|
||||
assigningToNobody = selectedIDs.length is 0
|
||||
|
||||
@state.set errors: { assigningToNobody, assigningToUnenrolled }
|
||||
|
||||
@assignCourse courseID, members
|
||||
|
||||
window.tracker?.trackEvent 'Teachers Class Students Assign Selected', category: 'Teachers', classroomID: @classroom.id, courseID: courseID, ['Mixpanel']
|
||||
|
||||
# TODO: Move this to the model. Use promises/callbacks?
|
||||
assignCourse: (courseID, members) ->
|
||||
courseInstance = @courseInstances.findWhere({ courseID, classroomID: @classroom.id })
|
||||
|
|
|
@ -17,13 +17,16 @@ helper = require 'lib/coursesHelper'
|
|||
module.exports = class TeacherClassesView extends RootView
|
||||
id: 'teacher-classes-view'
|
||||
template: template
|
||||
|
||||
|
||||
events:
|
||||
'click .edit-classroom': 'onClickEditClassroom'
|
||||
'click .archive-classroom': 'onClickArchiveClassroom'
|
||||
'click .unarchive-classroom': 'onClickUnarchiveClassroom'
|
||||
'click .add-students-btn': 'onClickAddStudentsButton'
|
||||
'click .create-classroom-btn': 'onClickCreateClassroomButton'
|
||||
'click .create-teacher-btn': 'onClickCreateTeacherButton'
|
||||
'click .update-teacher-btn': 'onClickUpdateTeacherButton'
|
||||
'click .view-class-btn': 'onClickViewClassButton'
|
||||
|
||||
getTitle: -> return $.i18n.t('teacher.my_classes')
|
||||
|
||||
|
@ -38,18 +41,19 @@ module.exports = class TeacherClassesView extends RootView
|
|||
jqxhrs = classroom.sessions.fetchForAllClassroomMembers(classroom)
|
||||
if jqxhrs.length > 0
|
||||
@supermodel.trackCollection(classroom.sessions)
|
||||
|
||||
window.tracker?.trackEvent 'Teachers Classes Loaded', category: 'Teachers', ['Mixpanel']
|
||||
|
||||
@courses = new Courses()
|
||||
@courses.fetch()
|
||||
@supermodel.trackCollection(@courses)
|
||||
|
||||
|
||||
@courseInstances = new CourseInstances()
|
||||
@courseInstances.fetchByOwner(me.id)
|
||||
@supermodel.trackCollection(@courseInstances)
|
||||
@progressDotTemplate = require 'templates/teachers/hovers/progress-dot-whole-course'
|
||||
|
||||
|
||||
# Level Sessions loaded after onLoaded to prevent race condition in calculateDots
|
||||
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
$('.progress-dot').each (i, el) ->
|
||||
|
@ -58,52 +62,71 @@ module.exports = class TeacherClassesView extends RootView
|
|||
html: true
|
||||
container: dot
|
||||
})
|
||||
|
||||
|
||||
onLoaded: ->
|
||||
helper.calculateDots(@classrooms, @courses, @courseInstances)
|
||||
super()
|
||||
|
||||
|
||||
onClickEditClassroom: (e) ->
|
||||
classroomID = $(e.target).data('classroom-id')
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Teachers', classroomID: classroomID, ['Mixpanel']
|
||||
classroom = @classrooms.get(classroomID)
|
||||
modal = new ClassroomSettingsModal({ classroom: classroom })
|
||||
@openModalView(modal)
|
||||
@listenToOnce modal, 'hide', @render
|
||||
|
||||
onClickCreateClassroomButton: (e) ->
|
||||
window.tracker?.trackEvent 'Teachers Classes Create New Class Started', category: 'Teachers', ['Mixpanel']
|
||||
classroom = new Classroom({ ownerID: me.id })
|
||||
modal = new ClassroomSettingsModal({ classroom: classroom })
|
||||
@openModalView(modal)
|
||||
@listenToOnce modal.classroom, 'sync', ->
|
||||
window.tracker?.trackEvent 'Teachers Classes Create New Class Finished', category: 'Teachers', ['Mixpanel']
|
||||
@classrooms.add(modal.classroom)
|
||||
@addFreeCourseInstances()
|
||||
@render()
|
||||
|
||||
|
||||
onClickCreateTeacherButton: (e) ->
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Teachers', ['Mixpanel']
|
||||
application.router.navigate("/teachers/signup", { trigger: true })
|
||||
|
||||
onClickUpdateTeacherButton: (e) ->
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Teachers', ['Mixpanel']
|
||||
application.router.navigate("/teachers/update-account", { trigger: true })
|
||||
|
||||
onClickAddStudentsButton: (e) ->
|
||||
window.tracker?.trackEvent 'Teachers Classes Add Students Started', category: 'Teachers', ['Mixpanel']
|
||||
classroomID = $(e.currentTarget).data('classroom-id')
|
||||
classroom = @classrooms.get(classroomID)
|
||||
modal = new InviteToClassroomModal({ classroom: classroom })
|
||||
@openModalView(modal)
|
||||
@listenToOnce modal, 'hide', @render
|
||||
|
||||
|
||||
onClickArchiveClassroom: (e) ->
|
||||
classroomID = $(e.currentTarget).data('classroom-id')
|
||||
classroom = @classrooms.get(classroomID)
|
||||
classroom.set('archived', true)
|
||||
classroom.save {}, {
|
||||
success: =>
|
||||
window.tracker?.trackEvent 'Teachers Classes Archived Class', category: 'Teachers', ['Mixpanel']
|
||||
@render()
|
||||
}
|
||||
|
||||
|
||||
onClickUnarchiveClassroom: (e) ->
|
||||
classroomID = $(e.currentTarget).data('classroom-id')
|
||||
classroom = @classrooms.get(classroomID)
|
||||
classroom.set('archived', false)
|
||||
classroom.save {}, {
|
||||
success: =>
|
||||
window.tracker?.trackEvent 'Teachers Classes Unarchived Class', category: 'Teachers', ['Mixpanel']
|
||||
@render()
|
||||
}
|
||||
|
||||
|
||||
onClickViewClassButton: (e) ->
|
||||
classroomID = $(e.target).data('classroom-id')
|
||||
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Teachers', classroomID: classroomID, ['Mixpanel']
|
||||
application.router.navigate("/teachers/classes/#{classroomID}", { trigger: true })
|
||||
|
||||
addFreeCourseInstances: ->
|
||||
# so that when students join the classroom, they can automatically get free courses
|
||||
# non-free courses are generated when the teacher first adds a student to them
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
ActivateLicensesModal = require 'views/courses/ActivateLicensesModal'
|
||||
app = require 'core/application'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
CocoModel = require 'models/CocoModel'
|
||||
|
@ -6,24 +5,19 @@ Course = require 'models/Course'
|
|||
Campaigns = require 'collections/Campaigns'
|
||||
Classroom = require 'models/Classroom'
|
||||
Classrooms = require 'collections/Classrooms'
|
||||
InviteToClassroomModal = require 'views/courses/InviteToClassroomModal'
|
||||
User = require 'models/User'
|
||||
CourseInstance = require 'models/CourseInstance'
|
||||
RootView = require 'views/core/RootView'
|
||||
template = require 'templates/courses/teacher-courses-view'
|
||||
ClassroomSettingsModal = require 'views/courses/ClassroomSettingsModal'
|
||||
|
||||
module.exports = class TeacherCoursesView extends RootView
|
||||
id: 'teacher-courses-view'
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click #activate-licenses-btn': 'onClickActivateLicensesButton'
|
||||
'click .btn-add-students': 'onClickAddStudents'
|
||||
'click .create-new-class': 'onClickCreateNewClassButton'
|
||||
'click .edit-classroom-small': 'onClickEditClassroomSmall'
|
||||
'click .guide-btn': 'onClickGuideButton'
|
||||
'click .play-level-button': 'onClickPlayLevel'
|
||||
|
||||
|
||||
guideLinks:
|
||||
{
|
||||
"560f1a9f22961295f9427742":
|
||||
|
@ -48,91 +42,25 @@ module.exports = class TeacherCoursesView extends RootView
|
|||
@supermodel.trackCollection(@ownedClassrooms)
|
||||
@courses = new CocoCollection([], { url: "/db/course", model: Course})
|
||||
@supermodel.loadCollection(@courses, 'courses')
|
||||
@classrooms = new CocoCollection([], { url: "/db/classroom", model: Classroom })
|
||||
@classrooms.comparator = '_id'
|
||||
@listenToOnce @classrooms, 'sync', @onceClassroomsSync
|
||||
@supermodel.loadCollection(@classrooms, 'classrooms', {data: {ownerID: me.id}})
|
||||
@campaigns = new Campaigns()
|
||||
@supermodel.trackRequest @campaigns.fetchByType('course', { data: { project: 'levels,levelsUpdated' } })
|
||||
@courseInstances = new CocoCollection([], { url: "/db/course_instance", model: CourseInstance })
|
||||
@courseInstances.comparator = 'courseID'
|
||||
@courseInstances.sliceWithMembers = -> return @filter (courseInstance) -> _.size(courseInstance.get('members')) and courseInstance.get('classroomID')
|
||||
@supermodel.loadCollection(@courseInstances, 'course_instances', {data: {ownerID: me.id}})
|
||||
@members = new CocoCollection([], { model: User })
|
||||
@listenTo @members, 'sync', @render
|
||||
@
|
||||
|
||||
onceClassroomsSync: ->
|
||||
for classroom in @classrooms.models
|
||||
@members.fetch({
|
||||
remove: false
|
||||
url: "/db/classroom/#{classroom.id}/members"
|
||||
})
|
||||
initialize: (options) ->
|
||||
window.tracker?.trackEvent 'Classes Guides Loaded', category: 'Teachers', ['Mixpanel']
|
||||
super(options)
|
||||
|
||||
onClickActivateLicensesButton: ->
|
||||
modal = new ActivateLicensesModal({
|
||||
users: @members
|
||||
})
|
||||
@openModalView(modal)
|
||||
modal.once 'redeem-users', -> document.location.reload()
|
||||
application.tracker?.trackEvent 'Courses teachers started enroll students', category: 'Courses'
|
||||
onClickGuideButton: (e) ->
|
||||
courseID = $(e.currentTarget).data('course-id')
|
||||
courseName = $(e.currentTarget).data('course-name')
|
||||
eventAction = $(e.currentTarget).data('event-action')
|
||||
window.tracker?.trackEvent eventAction, category: 'Teachers', courseID: courseID, courseName: courseName, ['Mixpanel']
|
||||
|
||||
onClickAddStudents: (e) ->
|
||||
classroomID = $(e.target).data('classroom-id')
|
||||
classroom = @classrooms.get(classroomID)
|
||||
unless classroom
|
||||
console.error 'No classroom ID found.'
|
||||
return
|
||||
modal = new InviteToClassroomModal({classroom: classroom})
|
||||
@openModalView(modal)
|
||||
application.tracker?.trackEvent 'Classroom started add students', category: 'Courses', classroomID: classroom.id
|
||||
|
||||
onClickCreateNewClassButton: ->
|
||||
return application.router.navigate('/teachers/signup', {trigger: true}) if me.get('anonymous')
|
||||
modal = new ClassroomSettingsModal({})
|
||||
@openModalView(modal)
|
||||
@listenToOnce modal, 'hide', =>
|
||||
# TODO: how to get new classroom from modal?
|
||||
@classrooms.add(modal.classroom)
|
||||
# TODO: will this definitely fire after modal saves new classroom?
|
||||
@listenToOnce modal.classroom, 'sync', ->
|
||||
@addFreeCourseInstances()
|
||||
@render()
|
||||
|
||||
onClickEditClassroomSmall: (e) ->
|
||||
classroomID = $(e.target).data('classroom-id')
|
||||
classroom = @classrooms.get(classroomID)
|
||||
modal = new ClassroomSettingsModal({classroom: classroom})
|
||||
@openModalView(modal)
|
||||
@listenToOnce modal, 'hide', @render
|
||||
|
||||
onClickPlayLevel: (e) ->
|
||||
form = $(e.currentTarget).closest('.play-level-form')
|
||||
levelSlug = form.find('.level-select').val()
|
||||
courseID = form.data('course-id')
|
||||
language = form.find('.language-select').val()
|
||||
window.tracker?.trackEvent 'Classes Guides Play Level', category: 'Teachers', courseID: courseID, language: language, levelSlug: levelSlug, ['Mixpanel']
|
||||
url = "/play/level/#{levelSlug}?course=#{courseID}&codeLanguage=#{language}"
|
||||
application.router.navigate(url, { trigger: true })
|
||||
|
||||
onLoaded: ->
|
||||
super()
|
||||
@addFreeCourseInstances()
|
||||
|
||||
addFreeCourseInstances: ->
|
||||
# so that when students join the classroom, they can automatically get free courses
|
||||
# non-free courses are generated when the teacher first adds a student to them
|
||||
for classroom in @classrooms.models
|
||||
for course in @courses.models
|
||||
continue if not course.get('free')
|
||||
courseInstance = @courseInstances.findWhere({classroomID: classroom.id, courseID: course.id})
|
||||
if not courseInstance
|
||||
courseInstance = new CourseInstance({
|
||||
classroomID: classroom.id
|
||||
courseID: course.id
|
||||
})
|
||||
# TODO: figure out a better way to get around triggering validation errors for properties
|
||||
# that the server will end up filling in, like an empty members array, ownerID
|
||||
courseInstance.save(null, {validate: false})
|
||||
@courseInstances.add(courseInstance)
|
||||
@listenToOnce courseInstance, 'sync', @addFreeCourseInstances
|
||||
return
|
||||
|
|
|
@ -34,7 +34,8 @@ module.exports = class ControlBarView extends CocoView
|
|||
@worldName = options.worldName
|
||||
@session = options.session
|
||||
@level = options.level
|
||||
@levelID = @level.get('slug') or @level.id
|
||||
@levelSlug = @level.get('slug')
|
||||
@levelID = @levelSlug or @level.id
|
||||
@spectateGame = options.spectateGame ? false
|
||||
@observing = options.session.get('creator') isnt me.id
|
||||
super options
|
||||
|
@ -121,6 +122,9 @@ module.exports = class ControlBarView extends CocoView
|
|||
@setupManager.open()
|
||||
|
||||
onClickHome: (e) ->
|
||||
if @level.get('type', true) in ['course']
|
||||
category = if me.isTeacher() then 'Teachers' else 'Students'
|
||||
window.tracker?.trackEvent 'Play Level Back To Levels', category: category, levelSlug: @levelSlug, ['Mixpanel']
|
||||
e.preventDefault()
|
||||
e.stopImmediatePropagation()
|
||||
Backbone.Mediator.publish 'router:navigate', route: @homeLink, viewClass: @homeViewClass, viewArgs: @homeViewArgs
|
||||
|
|
|
@ -56,6 +56,7 @@ module.exports = class CourseVictoryModal extends ModalView
|
|||
@levelSessions = @supermodel.loadCollection(@levelSessions, 'sessions', {
|
||||
data: { project: 'state.complete level.original playtime changed' }
|
||||
}).model
|
||||
window.tracker?.trackEvent 'Play Level Victory Modal Loaded', category: 'Students', levelSlug: @level.get('slug'), ['Mixpanel']
|
||||
|
||||
onResourceLoadFailed: (e) ->
|
||||
if e.resource.jqxhr is @nextLevelRequest
|
||||
|
@ -158,6 +159,7 @@ module.exports = class CourseVictoryModal extends ModalView
|
|||
@showView(@views[index+1])
|
||||
|
||||
onNextLevel: ->
|
||||
window.tracker?.trackEvent 'Play Level Victory Modal Next Level', category: 'Students', levelSlug: @level.get('slug'), nextLevelSlug: @nextLevel.get('slug'), ['Mixpanel']
|
||||
if me.isSessionless()
|
||||
link = "/play/level/#{@nextLevel.get('slug')}?course=#{@courseID}&codeLanguage=#{utils.getQueryVariable('codeLanguage', 'python')}"
|
||||
else
|
||||
|
@ -165,6 +167,7 @@ module.exports = class CourseVictoryModal extends ModalView
|
|||
application.router.navigate(link, {trigger: true})
|
||||
|
||||
onDone: ->
|
||||
window.tracker?.trackEvent 'Play Level Victory Modal Done', category: 'Students', levelSlug: @level.get('slug'), ['Mixpanel']
|
||||
if me.isSessionless()
|
||||
link = "/teachers/courses"
|
||||
else
|
||||
|
|
|
@ -33,6 +33,7 @@ module.exports = class ConvertToTeacherAccountView extends RootView
|
|||
@trialRequests = new TrialRequests()
|
||||
@trialRequests.fetchOwn()
|
||||
@supermodel.trackCollection(@trialRequests)
|
||||
window.tracker?.trackEvent 'Teachers Convert Account Loaded', category: 'Teachers', ['Mixpanel']
|
||||
|
||||
onLeaveMessage: ->
|
||||
if @formChanged
|
||||
|
@ -87,6 +88,8 @@ module.exports = class ConvertToTeacherAccountView extends RootView
|
|||
@onChangeForm()
|
||||
|
||||
onChangeForm: ->
|
||||
unless @formChanged
|
||||
window.tracker?.trackEvent 'Teachers Convert Account Form Started', category: 'Teachers', ['Mixpanel']
|
||||
@formChanged = true
|
||||
|
||||
onSubmitForm: (e) ->
|
||||
|
@ -141,6 +144,7 @@ module.exports = class ConvertToTeacherAccountView extends RootView
|
|||
errors.showNotyNetworkError(arguments...)
|
||||
|
||||
onTrialRequestSubmit: ->
|
||||
window.tracker?.trackEvent 'Teachers Convert Account Submitted', category: 'Teachers', ['Mixpanel']
|
||||
@formChanged = false
|
||||
me.setRole @trialRequest.get('properties').role.toLowerCase(), true
|
||||
application.router.navigate('/teachers/classes', {trigger: true})
|
||||
|
|
|
@ -31,6 +31,7 @@ module.exports = class CreateTeacherAccountView extends RootView
|
|||
@trialRequests = new TrialRequests()
|
||||
@trialRequests.fetchOwn()
|
||||
@supermodel.trackCollection(@trialRequests)
|
||||
window.tracker?.trackEvent 'Teachers Create Account Loaded', category: 'Teachers', ['Mixpanel']
|
||||
|
||||
onLeaveMessage: ->
|
||||
if @formChanged
|
||||
|
@ -39,8 +40,6 @@ module.exports = class CreateTeacherAccountView extends RootView
|
|||
onLoaded: ->
|
||||
if @trialRequests.size()
|
||||
@trialRequest = @trialRequests.first()
|
||||
if @trialRequest and @trialRequest.get('status') isnt 'submitted' and @trialRequest.get('status') isnt 'approved'
|
||||
window.tracker?.trackEvent 'View Trial Request', category: 'Teachers', label: 'View Trial Request', ['Mixpanel']
|
||||
super()
|
||||
|
||||
invalidateNCES: ->
|
||||
|
@ -90,6 +89,8 @@ module.exports = class CreateTeacherAccountView extends RootView
|
|||
@openModalView(modal)
|
||||
|
||||
onChangeForm: ->
|
||||
unless @formChanged
|
||||
window.tracker?.trackEvent 'Teachers Create Account Form Started', category: 'Teachers', ['Mixpanel']
|
||||
@formChanged = true
|
||||
|
||||
onSubmitForm: (e) ->
|
||||
|
@ -158,6 +159,7 @@ module.exports = class CreateTeacherAccountView extends RootView
|
|||
@openModalView(modal)
|
||||
|
||||
onTrialRequestSubmit: ->
|
||||
window.tracker?.trackEvent 'Teachers Create Account Submitted', category: 'Teachers', ['Mixpanel']
|
||||
@formChanged = false
|
||||
attrs = _.pick(forms.formToObject(@$('form')), 'name', 'email', 'role')
|
||||
attrs.role = attrs.role.toLowerCase()
|
||||
|
|
|
@ -34,6 +34,7 @@ module.exports = class RequestQuoteView extends RootView
|
|||
@trialRequests.fetchOwn()
|
||||
@supermodel.trackCollection(@trialRequests)
|
||||
@formChanged = false
|
||||
window.tracker?.trackEvent 'Teachers Request Demo Loaded', category: 'Teachers', ['Mixpanel']
|
||||
|
||||
onLeaveMessage: ->
|
||||
if @formChanged
|
||||
|
@ -42,8 +43,6 @@ module.exports = class RequestQuoteView extends RootView
|
|||
onLoaded: ->
|
||||
if @trialRequests.size()
|
||||
@trialRequest = @trialRequests.first()
|
||||
if @trialRequest and @trialRequest.get('status') isnt 'submitted' and @trialRequest.get('status') isnt 'approved'
|
||||
window.tracker?.trackEvent 'View Trial Request', category: 'Teachers', label: 'View Trial Request', ['Mixpanel']
|
||||
super()
|
||||
|
||||
invalidateNCES: ->
|
||||
|
@ -89,6 +88,8 @@ module.exports = class RequestQuoteView extends RootView
|
|||
@onChangeRequestForm()
|
||||
|
||||
onChangeRequestForm: ->
|
||||
unless @formChanged
|
||||
window.tracker?.trackEvent 'Teachers Request Demo Form Started', category: 'Teachers', ['Mixpanel']
|
||||
@formChanged = true
|
||||
|
||||
onSubmitRequestForm: (e) ->
|
||||
|
@ -161,6 +162,7 @@ module.exports = class RequestQuoteView extends RootView
|
|||
@openModalView(modal)
|
||||
|
||||
onTrialRequestSubmit: ->
|
||||
window.tracker?.trackEvent 'Teachers Request Demo Form Submitted', category: 'Teachers', ['Mixpanel']
|
||||
@formChanged = false
|
||||
me.setRole @trialRequest.get('properties').role.toLowerCase(), true
|
||||
defaultName = [@trialRequest.get('firstName'), @trialRequest.get('lastName')].join(' ')
|
||||
|
@ -168,7 +170,6 @@ module.exports = class RequestQuoteView extends RootView
|
|||
@$('#request-form, #form-submit-success').toggleClass('hide')
|
||||
@scrollToTop(0)
|
||||
$('#flying-focus').css({top: 0, left: 0}) # Hack copied from Router.coffee#187. Ideally we'd swap out the view and have view-swapping logic handle this
|
||||
window.tracker?.trackEvent 'Submit Trial Request', category: 'Teachers', label: 'Trial Request', ['Mixpanel']
|
||||
|
||||
onClickGPlusSignupButton: ->
|
||||
btn = @$('#gplus-signup-btn')
|
||||
|
@ -190,6 +191,7 @@ module.exports = class RequestQuoteView extends RootView
|
|||
url: "/db/user?gplusID=#{gplusAttrs.gplusID}&gplusAccessToken=#{application.gplusHandler.token()}"
|
||||
type: 'PUT'
|
||||
success: ->
|
||||
window.tracker?.trackEvent 'Teachers Request Demo Create Account Google', category: 'Teachers', ['Mixpanel']
|
||||
application.router.navigate(SIGNUP_REDIRECT)
|
||||
window.location.reload()
|
||||
error: errors.showNotyNetworkError
|
||||
|
@ -218,6 +220,7 @@ module.exports = class RequestQuoteView extends RootView
|
|||
url: "/db/user?facebookID=#{facebookAttrs.facebookID}&facebookAccessToken=#{application.facebookHandler.token()}"
|
||||
type: 'PUT'
|
||||
success: ->
|
||||
window.tracker?.trackEvent 'Teachers Request Demo Create Account Facebook', category: 'Teachers', ['Mixpanel']
|
||||
application.router.navigate(SIGNUP_REDIRECT)
|
||||
window.location.reload()
|
||||
error: errors.showNotyNetworkError
|
||||
|
@ -250,13 +253,12 @@ module.exports = class RequestQuoteView extends RootView
|
|||
})
|
||||
me.save(null, {
|
||||
success: ->
|
||||
window.tracker?.trackEvent 'Teachers Request Demo Create Account', category: 'Teachers', ['Mixpanel']
|
||||
application.router.navigate(SIGNUP_REDIRECT)
|
||||
window.location.reload()
|
||||
error: errors.showNotyNetworkError
|
||||
})
|
||||
|
||||
|
||||
|
||||
requestFormSchemaAnonymous = {
|
||||
type: 'object'
|
||||
required: [
|
||||
|
|
|
@ -2,4 +2,7 @@ RootView = require 'views/core/RootView'
|
|||
|
||||
module.exports = class RestrictedToTeachersView extends RootView
|
||||
id: 'restricted-to-teachers-view'
|
||||
template: require 'templates/teachers/restricted-to-teachers-view'
|
||||
template: require 'templates/teachers/restricted-to-teachers-view'
|
||||
|
||||
initialize: ->
|
||||
window.tracker?.trackEvent 'Restricted To Teachers Loaded', category: 'Students', ['Mixpanel']
|
||||
|
|
Loading…
Reference in a new issue