2015-09-10 13:37:32 -04:00
|
|
|
app = require 'core/application'
|
|
|
|
RootView = require 'views/core/RootView'
|
2015-11-03 19:41:06 -05:00
|
|
|
template = require 'templates/courses/courses-view'
|
2016-04-27 19:25:10 -04:00
|
|
|
AuthModal = require 'views/core/AuthModal'
|
|
|
|
CreateAccountModal = require 'views/core/CreateAccountModal'
|
2015-11-23 12:52:15 -05:00
|
|
|
ChangeCourseLanguageModal = require 'views/courses/ChangeCourseLanguageModal'
|
2016-05-25 18:24:51 -04:00
|
|
|
HeroSelectModal = require 'views/courses/HeroSelectModal'
|
2015-11-29 18:41:57 -05:00
|
|
|
ChooseLanguageModal = require 'views/courses/ChooseLanguageModal'
|
2016-05-11 17:39:26 -04:00
|
|
|
JoinClassModal = require 'views/courses/JoinClassModal'
|
2015-11-21 14:38:34 -05:00
|
|
|
CourseInstance = require 'models/CourseInstance'
|
2015-11-22 03:08:46 -05:00
|
|
|
CocoCollection = require 'collections/CocoCollection'
|
|
|
|
Course = require 'models/Course'
|
|
|
|
Classroom = require 'models/Classroom'
|
2016-03-30 19:20:37 -04:00
|
|
|
Classrooms = require 'collections/Classrooms'
|
2015-11-22 03:08:46 -05:00
|
|
|
LevelSession = require 'models/LevelSession'
|
2016-09-01 19:20:00 -04:00
|
|
|
Levels = require 'collections/Levels'
|
2016-08-17 17:15:36 -04:00
|
|
|
NameLoader = require 'core/NameLoader'
|
2015-11-23 11:46:08 -05:00
|
|
|
Campaign = require 'models/Campaign'
|
2016-05-25 18:24:51 -04:00
|
|
|
ThangType = require 'models/ThangType'
|
2015-11-29 18:13:23 -05:00
|
|
|
utils = require 'core/utils'
|
2015-11-23 11:46:08 -05:00
|
|
|
|
|
|
|
# TODO: Test everything
|
2015-10-12 19:25:23 -04:00
|
|
|
|
2015-08-29 10:15:35 -04:00
|
|
|
module.exports = class CoursesView extends RootView
|
|
|
|
id: 'courses-view'
|
|
|
|
template: template
|
2015-11-21 14:38:34 -05:00
|
|
|
|
|
|
|
events:
|
|
|
|
'click #log-in-btn': 'onClickLogInButton'
|
2016-04-27 19:25:10 -04:00
|
|
|
'click #start-new-game-btn': 'openSignUpModal'
|
2016-05-25 18:24:51 -04:00
|
|
|
'click .change-hero-btn': 'onClickChangeHeroButton'
|
2015-11-23 11:46:08 -05:00
|
|
|
'click #join-class-btn': 'onClickJoinClassButton'
|
|
|
|
'submit #join-class-form': 'onSubmitJoinClassForm'
|
2016-06-08 09:24:59 -04:00
|
|
|
'click .play-btn': 'onClickPlay'
|
|
|
|
'click .view-class-btn': 'onClickViewClass'
|
|
|
|
'click .view-levels-btn': 'onClickViewLevels'
|
2015-12-04 15:08:08 -05:00
|
|
|
|
2016-05-27 12:40:46 -04:00
|
|
|
getTitle: -> return $.i18n.t('teacher.students')
|
|
|
|
|
2015-11-22 03:08:46 -05:00
|
|
|
initialize: ->
|
2016-06-08 09:24:59 -04:00
|
|
|
@classCodeQueryVar = utils.getQueryVariable('_cc', false)
|
2015-11-22 03:08:46 -05:00
|
|
|
@courseInstances = new CocoCollection([], { url: "/db/user/#{me.id}/course_instances", model: CourseInstance})
|
|
|
|
@courseInstances.comparator = (ci) -> return ci.get('classroomID') + ci.get('courseID')
|
2015-11-29 15:25:59 -05:00
|
|
|
@listenToOnce @courseInstances, 'sync', @onCourseInstancesLoaded
|
2016-06-14 20:15:48 -04:00
|
|
|
@supermodel.loadCollection(@courseInstances, { cache: false })
|
2016-08-31 13:47:14 -04:00
|
|
|
@classrooms = new CocoCollection([], { url: "/db/classroom", model: Classroom})
|
|
|
|
@classrooms.comparator = (a, b) -> b.id.localeCompare(a.id)
|
2016-06-14 17:27:57 -04:00
|
|
|
@supermodel.loadCollection(@classrooms, { data: {memberID: me.id}, cache: false })
|
2016-03-30 19:20:37 -04:00
|
|
|
@ownedClassrooms = new Classrooms()
|
|
|
|
@ownedClassrooms.fetchMine({data: {project: '_id'}})
|
|
|
|
@supermodel.trackCollection(@ownedClassrooms)
|
2015-11-22 03:08:46 -05:00
|
|
|
@courses = new CocoCollection([], { url: "/db/course", model: Course})
|
2016-01-25 19:52:14 -05:00
|
|
|
@supermodel.loadCollection(@courses)
|
2016-09-01 19:20:00 -04:00
|
|
|
@originalLevelMap = {}
|
|
|
|
@urls = require('core/urls')
|
2015-11-23 11:46:08 -05:00
|
|
|
|
2016-05-25 18:24:51 -04:00
|
|
|
# TODO: Trim this section for only what's necessary
|
|
|
|
@hero = new ThangType
|
|
|
|
defaultHeroOriginal = ThangType.heroes.captain
|
|
|
|
heroOriginal = me.get('heroConfig')?.thangType or defaultHeroOriginal
|
|
|
|
@hero.url = "/db/thang.type/#{heroOriginal}/version"
|
|
|
|
# @hero.setProjection ['name','slug','soundTriggers','featureImages','gems','heroClass','description','components','extendedName','unlockLevelName','i18n']
|
|
|
|
@supermodel.loadModel(@hero, 'hero')
|
|
|
|
@listenTo @hero, 'all', ->
|
|
|
|
@render()
|
2016-06-08 09:24:59 -04:00
|
|
|
window.tracker?.trackEvent 'Students Loaded', category: 'Students', ['Mixpanel']
|
2016-08-17 17:15:36 -04:00
|
|
|
|
2016-06-14 20:15:48 -04:00
|
|
|
afterInsert: ->
|
|
|
|
super()
|
|
|
|
unless me.isStudent() or (@classCodeQueryVar and not me.isTeacher())
|
|
|
|
@onClassLoadError()
|
2016-05-25 18:24:51 -04:00
|
|
|
|
2015-11-29 15:25:59 -05:00
|
|
|
onCourseInstancesLoaded: ->
|
2015-11-23 11:46:08 -05:00
|
|
|
for courseInstance in @courseInstances.models
|
2016-09-06 15:43:06 -04:00
|
|
|
continue if not courseInstance.get('classroomID')
|
2015-11-29 15:25:59 -05:00
|
|
|
courseID = courseInstance.get('courseID')
|
2016-08-31 20:04:40 -04:00
|
|
|
courseInstance.sessions = new CocoCollection([], {
|
2015-11-29 15:25:59 -05:00
|
|
|
url: courseInstance.url() + '/my-course-level-sessions',
|
2015-12-04 15:08:08 -05:00
|
|
|
model: LevelSession
|
2015-11-29 15:25:59 -05:00
|
|
|
})
|
|
|
|
courseInstance.sessions.comparator = 'changed'
|
2016-01-25 19:52:14 -05:00
|
|
|
@supermodel.loadCollection(courseInstance.sessions, { data: { project: 'state.complete level.original playtime changed' }})
|
2015-12-04 15:08:08 -05:00
|
|
|
|
2016-04-13 12:54:24 -04:00
|
|
|
hocCourseInstance = @courseInstances.findWhere({hourOfCode: true})
|
|
|
|
if hocCourseInstance
|
|
|
|
@courseInstances.remove(hocCourseInstance)
|
2015-12-04 15:08:08 -05:00
|
|
|
|
2015-11-29 18:13:23 -05:00
|
|
|
onLoaded: ->
|
2015-11-29 18:20:38 -05:00
|
|
|
super()
|
2016-06-08 09:24:59 -04:00
|
|
|
if @classCodeQueryVar and not me.isAnonymous()
|
|
|
|
window.tracker?.trackEvent 'Students Join Class Link', category: 'Students', classCode: @classCodeQueryVar, ['Mixpanel']
|
2015-11-29 18:13:23 -05:00
|
|
|
@joinClass()
|
2016-06-30 18:32:58 -04:00
|
|
|
else if @classCodeQueryVar and me.isAnonymous()
|
|
|
|
@openModalView(new CreateAccountModal())
|
2016-08-17 17:15:36 -04:00
|
|
|
ownerIDs = _.map(@classrooms.models, (c) -> c.get('ownerID')) ? []
|
|
|
|
Promise.resolve($.ajax(NameLoader.loadNames(ownerIDs)))
|
|
|
|
.then(=>
|
|
|
|
@ownerNameMap = {}
|
|
|
|
@ownerNameMap[ownerID] = NameLoader.getName(ownerID) for ownerID in ownerIDs
|
|
|
|
@render?()
|
|
|
|
)
|
2016-09-01 19:20:00 -04:00
|
|
|
_.forEach _.unique(_.pluck(@classrooms.models, 'id')), (classroomID) =>
|
|
|
|
levels = new Levels()
|
|
|
|
@listenTo levels, 'sync', =>
|
|
|
|
return if @destroyed
|
|
|
|
@originalLevelMap[level.get('original')] = level for level in levels.models
|
|
|
|
@render()
|
|
|
|
@supermodel.trackRequest(levels.fetchForClassroom(classroomID, { data: { project: 'original,primerLanguage,slug' }}))
|
2015-11-29 15:25:59 -05:00
|
|
|
|
2015-11-21 14:38:34 -05:00
|
|
|
onClickLogInButton: ->
|
2016-04-27 19:25:10 -04:00
|
|
|
modal = new AuthModal()
|
2015-11-21 14:38:34 -05:00
|
|
|
@openModalView(modal)
|
2016-06-08 09:24:59 -04:00
|
|
|
window.tracker?.trackEvent 'Students Login Started', category: 'Students', ['Mixpanel']
|
2015-11-21 14:38:34 -05:00
|
|
|
|
|
|
|
openSignUpModal: ->
|
2016-06-08 09:24:59 -04:00
|
|
|
window.tracker?.trackEvent 'Students Signup Started', category: 'Students', ['Mixpanel']
|
2016-05-10 15:41:50 -04:00
|
|
|
modal = new CreateAccountModal({ initialValues: { classCode: utils.getQueryVariable('_cc', "") } })
|
2015-11-21 14:38:34 -05:00
|
|
|
@openModalView(modal)
|
|
|
|
|
2016-05-25 18:24:51 -04:00
|
|
|
onClickChangeHeroButton: ->
|
2016-06-08 09:24:59 -04:00
|
|
|
window.tracker?.trackEvent 'Students Change Hero Started', category: 'Students', ['Mixpanel']
|
2016-05-25 18:24:51 -04:00
|
|
|
modal = new HeroSelectModal({ currentHeroID: @hero.id })
|
|
|
|
@openModalView(modal)
|
|
|
|
@listenTo modal, 'hero-select:success', (newHero) =>
|
|
|
|
# @hero.url = "/db/thang.type/#{me.get('heroConfig').thangType}/version"
|
|
|
|
# @hero.fetch()
|
|
|
|
@hero.set(newHero.attributes)
|
|
|
|
@listenTo modal, 'hide', ->
|
|
|
|
@stopListening modal
|
|
|
|
|
2015-11-23 11:46:08 -05:00
|
|
|
onSubmitJoinClassForm: (e) ->
|
|
|
|
e.preventDefault()
|
2016-06-08 09:24:59 -04:00
|
|
|
classCode = @$('#class-code-input').val() or @classCodeQueryVar
|
|
|
|
window.tracker?.trackEvent 'Students Join Class With Code', category: 'Students', classCode: classCode, ['Mixpanel']
|
2015-11-23 11:46:08 -05:00
|
|
|
@joinClass()
|
2015-12-04 15:08:08 -05:00
|
|
|
|
2015-11-23 11:46:08 -05:00
|
|
|
onClickJoinClassButton: (e) ->
|
2016-06-08 09:24:59 -04:00
|
|
|
classCode = @$('#class-code-input').val() or @classCodeQueryVar
|
|
|
|
window.tracker?.trackEvent 'Students Join Class With Code', category: 'Students', classCode: classCode, ['Mixpanel']
|
2015-11-23 11:46:08 -05:00
|
|
|
@joinClass()
|
|
|
|
|
|
|
|
joinClass: ->
|
2015-11-29 18:13:23 -05:00
|
|
|
return if @state
|
2015-11-23 11:46:08 -05:00
|
|
|
@state = 'enrolling'
|
2015-11-29 18:13:23 -05:00
|
|
|
@errorMessage = null
|
2016-06-08 09:24:59 -04:00
|
|
|
@classCode = @$('#class-code-input').val() or @classCodeQueryVar
|
2015-11-29 18:13:23 -05:00
|
|
|
if not @classCode
|
|
|
|
@state = null
|
|
|
|
@errorMessage = 'Please enter a code.'
|
|
|
|
@renderSelectors '#join-class-form'
|
|
|
|
return
|
|
|
|
@renderSelectors '#join-class-form'
|
2016-05-20 17:52:04 -04:00
|
|
|
if me.get('emailVerified') or me.isStudent()
|
2016-05-11 17:39:26 -04:00
|
|
|
newClassroom = new Classroom()
|
|
|
|
jqxhr = newClassroom.joinWithCode(@classCode)
|
|
|
|
@listenTo newClassroom, 'join:success', -> @onJoinClassroomSuccess(newClassroom)
|
|
|
|
@listenTo newClassroom, 'join:error', -> @onJoinClassroomError(newClassroom, jqxhr)
|
|
|
|
else
|
|
|
|
modal = new JoinClassModal({ @classCode })
|
|
|
|
@openModalView modal
|
2016-06-14 20:15:48 -04:00
|
|
|
@listenTo modal, 'error', @onClassLoadError
|
2016-05-11 17:39:26 -04:00
|
|
|
@listenTo modal, 'join:success', @onJoinClassroomSuccess
|
|
|
|
@listenTo modal, 'join:error', @onJoinClassroomError
|
2016-06-14 20:15:48 -04:00
|
|
|
@listenToOnce modal, 'hidden', ->
|
|
|
|
unless me.isStudent()
|
|
|
|
@onClassLoadError()
|
2016-05-23 13:26:34 -04:00
|
|
|
@listenTo modal, 'hidden', ->
|
|
|
|
@state = null
|
|
|
|
@renderSelectors '#join-class-form'
|
2015-11-23 11:46:08 -05:00
|
|
|
|
2016-09-12 09:20:59 -04:00
|
|
|
# Super hacky way to patch users being able to join class while hiding /students from others
|
2016-06-14 20:15:48 -04:00
|
|
|
onClassLoadError: ->
|
|
|
|
_.defer ->
|
|
|
|
application.router.routeDirectly('courses/RestrictedToStudentsView')
|
|
|
|
|
2015-11-23 11:46:08 -05:00
|
|
|
onJoinClassroomError: (classroom, jqxhr, options) ->
|
2015-11-29 18:13:23 -05:00
|
|
|
@state = null
|
2015-11-23 11:46:08 -05:00
|
|
|
if jqxhr.status is 422
|
|
|
|
@errorMessage = 'Please enter a code.'
|
|
|
|
else if jqxhr.status is 404
|
2016-07-07 19:00:15 -04:00
|
|
|
@errorMessage = $.t('signup.classroom_not_found')
|
2015-11-23 11:46:08 -05:00
|
|
|
else
|
|
|
|
@errorMessage = "#{jqxhr.responseText}"
|
2015-12-04 15:08:08 -05:00
|
|
|
@renderSelectors '#join-class-form'
|
2015-11-23 11:46:08 -05:00
|
|
|
|
2016-04-07 17:55:42 -04:00
|
|
|
onJoinClassroomSuccess: (newClassroom, data, options) ->
|
2016-05-11 17:39:26 -04:00
|
|
|
@state = null
|
2015-11-23 11:46:08 -05:00
|
|
|
application.tracker?.trackEvent 'Joined classroom', {
|
2015-12-04 15:08:08 -05:00
|
|
|
category: 'Courses'
|
|
|
|
classCode: @classCode
|
|
|
|
classroomID: newClassroom.id
|
2015-11-23 11:46:08 -05:00
|
|
|
classroomName: newClassroom.get('name')
|
|
|
|
ownerID: newClassroom.get('ownerID')
|
|
|
|
}
|
|
|
|
@classrooms.add(newClassroom)
|
|
|
|
@render()
|
2015-11-29 18:13:23 -05:00
|
|
|
@classroomJustAdded = newClassroom.id
|
2015-12-04 15:08:08 -05:00
|
|
|
|
2015-11-23 11:46:08 -05:00
|
|
|
classroomCourseInstances = new CocoCollection([], { url: "/db/course_instance", model: CourseInstance })
|
2015-11-29 18:13:23 -05:00
|
|
|
classroomCourseInstances.fetch({ data: {classroomID: newClassroom.id} })
|
2015-11-23 11:46:08 -05:00
|
|
|
@listenToOnce classroomCourseInstances, 'sync', ->
|
2016-05-13 13:55:22 -04:00
|
|
|
# TODO: Smoother system for joining a classroom and course instances, without requiring page reload,
|
2016-05-25 18:24:51 -04:00
|
|
|
# and showing which class was just joined.
|
2016-05-13 13:55:22 -04:00
|
|
|
document.location.search = '' # Using document.location.reload() causes an infinite loop of reloading
|
2016-06-08 09:24:59 -04:00
|
|
|
|
|
|
|
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']
|
2016-09-12 09:20:59 -04:00
|
|
|
application.router.navigate("/students/#{classroomID}", { trigger: true })
|
2016-06-08 09:24:59 -04:00
|
|
|
|
|
|
|
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']
|
2016-09-12 09:20:59 -04:00
|
|
|
application.router.navigate("/students/#{courseID}/#{courseInstanceID}", { trigger: true })
|