codecombat/app/views/courses/TeacherCoursesView.coffee

213 lines
No EOL
8.2 KiB
CoffeeScript

app = require 'core/application'
AuthModal = require 'views/core/AuthModal'
CocoCollection = require 'collections/CocoCollection'
CocoModel = require 'models/CocoModel'
Course = require 'models/Course'
Classroom = require 'models/Classroom'
User = require 'models/User'
Prepaid = require 'models/Prepaid'
CourseInstance = require 'models/CourseInstance'
RootView = require 'views/core/RootView'
template = require 'templates/courses/teacher-courses-view'
utils = require 'core/utils'
InviteToClassroomModal = require 'views/courses/InviteToClassroomModal'
ClassroomSettingsModal = require 'views/courses/ClassroomSettingsModal'
module.exports = class TeacherCoursesView extends RootView
id: 'teacher-courses-view'
template: template
events:
'click #create-new-class-btn': 'onClickCreateNewclassButton'
'click .add-students-btn': 'onClickAddStudentsButton'
'click .course-instance-membership-checkbox': 'onClickCourseInstanceMembershipCheckbox'
'click #save-changes-btn': 'onClickSaveChangesButton'
'click #manage-tab-link': 'onClickManageTabLink'
'click .edit-classroom-small': 'onClickEditClassroomSmall'
constructor: (options) ->
super(options)
@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}})
@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 })
@prepaids = new CocoCollection([], { url: "/db/prepaid", model: Prepaid })
sum = (numbers) -> _.reduce(numbers, (a, b) -> a + b)
@prepaids.totalMaxRedeemers = -> sum((prepaid.get('maxRedeemers') for prepaid in @models)) or 0
@prepaids.totalRedeemers = -> sum((_.size(prepaid.get('redeemers')) for prepaid in @models)) or 0
@prepaids.comparator = '_id'
@supermodel.loadCollection(@prepaids, 'prepaids', {data: {creator: me.id}})
@listenTo @members, 'sync', @renderManageTab
@usersToRedeem = new CocoCollection([], { model: User })
@hoc = utils.getQueryVariable('hoc')
@
onceClassroomsSync: ->
for classroom in @classrooms.models
@members.fetch({
remove: false
url: "/db/classroom/#{classroom.id}/members"
})
onClickCreateNewclassButton: ->
name = @$('#new-classroom-name-input').val()
return unless name
classroom = new Classroom({ name: name })
classroom.save()
@classrooms.add(classroom)
classroom.saving = true
@renderManageTab()
@listenTo classroom, 'sync', ->
classroom.saving = false
@fillMissingCourseInstances()
renderManageTab: ->
isActive = @$('#manage-tab-pane').hasClass('active')
@renderSelectors('#manage-tab-pane')
@$('#manage-tab-pane').toggleClass('active', isActive)
onClickEditClassroomSmall: (e) ->
classroomID = $(e.target).closest('small').data('classroom-id')
classroom = @classrooms.get(classroomID)
modal = new ClassroomSettingsModal({classroom: classroom})
@openModalView(modal)
@listenToOnce modal, 'hide', @renderManageTab
onClickAddStudentsButton: (e) ->
classroomID = $(e.target).data('classroom-id')
classroom = @classrooms.get(classroomID)
modal = new InviteToClassroomModal({classroom: classroom})
@openModalView(modal)
onLoaded: ->
super()
@linkCourseIntancesToCourses()
@fillMissingCourseInstances()
linkCourseIntancesToCourses: ->
for courseInstance in @courseInstances.models
courseInstance.course = @courses.get(courseInstance.get('courseID'))
fillMissingCourseInstances: ->
# TODO: Give teachers control over which courses are enabled for a given class.
# Add/remove course instances and columns in the view to match.
for classroom in @classrooms.models
classroom.filling = false
for course in @courses.models
courseInstance = @courseInstances.findWhere({classroomID: classroom.id, courseID: course.id})
if not courseInstance
classroom.filling = true
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})
courseInstance.course = course
@courseInstances.add(courseInstance)
@listenToOnce courseInstance, 'sync', @fillMissingCourseInstances
@renderManageTab()
return
@renderManageTab()
onClickCourseInstanceMembershipCheckbox: ->
usersToRedeem = {}
checkedBoxes = @$('.course-instance-membership-checkbox:checked')
_.each checkedBoxes, (el) =>
$el = $(el)
userID = $el.data('user-id')
return if usersToRedeem[userID]
user = @members.get(userID)
return if user.get('coursePrepaidID')
courseInstanceID = $el.data('course-instance-id')
courseInstance = @courseInstances.get(courseInstanceID)
return if courseInstance.course.get('free')
usersToRedeem[userID] = user
@usersToRedeem = new CocoCollection(_.values(usersToRedeem), {model: User})
@numCourseInstancesToAddTo = checkedBoxes.length
@renderSelectors '#fixed-area'
onClickSaveChangesButton: ->
@$('.course-instance-membership-checkbox').attr('disabled', true)
checkedBoxes = @$('.course-instance-membership-checkbox:checked')
raw = _.map checkedBoxes, (el) =>
$el = $(el)
userID = $el.data('user-id')
courseInstanceID = $el.data('course-instance-id')
courseInstance = @courseInstances.get(courseInstanceID)
return {
courseInstance: courseInstance
userID: userID
}
@membershipAdditions = new CocoCollection(raw, { model: User }) # TODO: Allow collections not to have models defined?
@membershipAdditions.originalSize = @membershipAdditions.size()
@usersToRedeem.originalSize = @usersToRedeem.size()
@state = 'saving-changes'
@renderSelectors '#fixed-area'
@redeemUsers()
redeemUsers: ->
if not @usersToRedeem.size()
@addMemberships()
return
user = @usersToRedeem.first()
prepaid = @prepaids.find (prepaid) -> prepaid.openSpots()
$.ajax({
method: 'POST'
url: _.result(prepaid, 'url') + '/redeemers'
data: { userID: user.id }
context: @
success: ->
@usersToRedeem.remove(user)
@renderSelectors '#fixed-area'
@redeemUsers()
error: (jqxhr, textStatus, errorThrown) ->
if jqxhr.status is 402
@state = 'error'
@stateMessage = arguments[2]
else
@state = 'error'
@stateMessage = "#{jqxhr.status}: #{jqxhr.responseText}"
@renderSelectors '#fixed-area'
})
addMemberships: ->
if not @membershipAdditions.size()
@renderSelectors '#fixed-area'
document.location.reload()
return
membershipAddition = @membershipAdditions.first()
courseInstance = membershipAddition.get('courseInstance')
userID = membershipAddition.get('userID')
$.ajax({
method: 'POST'
url: _.result(courseInstance, 'url') + '/members'
data: { userID: userID }
context: @
success: ->
@membershipAdditions.remove(membershipAddition)
@renderSelectors '#fixed-area'
@addMemberships()
error: (jqxhr, textStatus, errorThrown) ->
if jqxhr.status is 402
@state = 'error'
@stateMessage = arguments[2]
else
@state = 'error'
@stateMessage = "#{jqxhr.status}: #{jqxhr.responseText}"
@renderSelectors '#fixed-area'
})
onClickManageTabLink: ->
@$('.nav-tabs a[href="#manage-tab-pane"]').tab('show')