codecombat/app/views/clans/ClanDetailsView.coffee

286 lines
11 KiB
CoffeeScript
Raw Normal View History

RootView = require 'views/core/RootView'
template = require 'templates/clans/clan-details'
app = require 'core/application'
AuthModal = require 'views/core/AuthModal'
2015-04-02 20:00:28 -04:00
CocoCollection = require 'collections/CocoCollection'
Campaign = require 'models/Campaign'
Clan = require 'models/Clan'
2015-04-03 14:05:37 -04:00
EarnedAchievement = require 'models/EarnedAchievement'
LevelSession = require 'models/LevelSession'
SubscribeModal = require 'views/core/SubscribeModal'
2015-04-03 19:44:35 -04:00
ThangType = require 'models/ThangType'
2015-04-02 20:00:28 -04:00
User = require 'models/User'
# TODO: Add message for clan not found
# TODO: Progress visual for premium levels?
# TODO: Add expanded level names toggle
# TODO: Only need campaign data if clan is private
module.exports = class ClanDetailsView extends RootView
id: 'clan-details-view'
template: template
events:
2015-04-02 14:44:18 -04:00
'click .delete-clan-btn': 'onDeleteClan'
'click .edit-description-save-btn': 'onEditDescriptionSave'
'click .edit-name-save-btn': 'onEditNameSave'
'click .join-clan-btn': 'onJoinClan'
'click .leave-clan-btn': 'onLeaveClan'
'click .progress-level-cell': 'onClickLevel'
2015-04-02 14:01:37 -04:00
'click .remove-member-btn': 'onRemoveMember'
'mouseenter .progress-level-cell': 'onMouseEnterPoint'
'mouseleave .progress-level-cell': 'onMouseLeavePoint'
constructor: (options, @clanID) ->
super options
2015-04-03 12:52:25 -04:00
@initData()
2015-04-02 20:00:28 -04:00
destroy: ->
@stopListening?()
2015-04-03 12:52:25 -04:00
initData: ->
2015-04-03 14:05:37 -04:00
@stats = {}
@campaigns = new CocoCollection([], { url: "/db/campaign", model: Campaign, comparator:'_id' })
2015-04-03 12:52:25 -04:00
@clan = new Clan _id: @clanID
2015-04-24 17:21:57 -04:00
@members = new CocoCollection([], { url: "/db/clan/#{@clanID}/members", model: User, comparator: 'nameLower' })
2015-04-03 14:05:37 -04:00
@memberAchievements = new CocoCollection([], { url: "/db/clan/#{@clanID}/member_achievements", model: EarnedAchievement, comparator:'_id' })
# MemberSessions: only loads creatorName, levelName, codeLanguage, submittedCodeLanguage for each session
@memberSessions = new CocoCollection([], { url: "/db/clan/#{@clanID}/member_sessions", model: LevelSession, comparator:'_id' })
2015-04-03 14:05:37 -04:00
2015-04-03 12:52:25 -04:00
@listenTo me, 'sync', => @render?()
@listenTo @campaigns, 'sync', @onCampaignSync
@listenTo @clan, 'sync', @onClanSync
@listenTo @members, 'sync', @onMembersSync
@listenTo @memberAchievements, 'sync', @onMemberAchievementsSync
@listenTo @memberSessions, 'sync', @onMemberSessionsSync
@supermodel.loadModel @campaigns, 'clan', cache: false
@supermodel.loadModel @clan, 'clan', cache: false
@supermodel.loadCollection(@members, 'members', {cache: false})
@supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false})
@supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false})
2015-04-03 12:52:25 -04:00
2015-04-03 19:44:35 -04:00
getRenderData: ->
context = super()
context.campaignLevelProgressions = @campaignLevelProgressions ? []
2015-04-03 19:44:35 -04:00
context.clan = @clan
if application.isProduction()
context.joinClanLink = "https://codecombat.com/clans/#{@clanID}"
else
context.joinClanLink = "http://localhost:3000/clans/#{@clanID}"
context.owner = @owner
context.memberAchievementsMap = @memberAchievementsMap
context.memberLanguageMap = @memberLanguageMap
context.memberLevelStateMap = @memberLevelMap ? {}
2015-04-16 18:26:14 -04:00
context.memberMaxLevelCount = @memberMaxLevelCount
2015-04-03 19:44:35 -04:00
context.members = @members?.models
context.isOwner = @clan.get('ownerID') is me.id
context.isMember = @clanID in (me.get('clans') ? [])
context.stats = @stats
# Find last campaign level for each user
lastUserCampaignLevelMap = {}
maxLastUserCampaignLevel = 0
if @campaigns.loaded
for campaign in @campaigns.models
campaignID = campaign.id
lastLevelIndex = 0
for levelID, level of campaign.get('levels')
levelSlug = level.slug
for member in context.members
if context.memberLevelStateMap[member.id]?[levelSlug]
lastUserCampaignLevelMap[member.id] ?= {}
lastUserCampaignLevelMap[member.id][campaignID] ?= {}
lastUserCampaignLevelMap[member.id][campaignID] =
levelSlug: levelSlug
index: lastLevelIndex
maxLastUserCampaignLevel = lastLevelIndex if lastLevelIndex > maxLastUserCampaignLevel
lastLevelIndex++
context.lastUserCampaignLevelMap = lastUserCampaignLevelMap
context.showExpandedProgress = maxLastUserCampaignLevel <= 30
2015-04-03 19:44:35 -04:00
context
afterRender: ->
super()
@updateHeroIcons()
2015-04-03 14:05:37 -04:00
refreshData: ->
me.fetch cache: false
@members.fetch cache: false
@memberAchievements.fetch cache: false
2015-04-16 18:26:14 -04:00
@memberSessions.fetch cache: false
2015-04-03 14:05:37 -04:00
2015-04-03 19:44:35 -04:00
updateHeroIcons: ->
return unless @members?.models?
for member in @members.models
continue unless hero = member.get('heroConfig')?.thangType
for slug, original of ThangType.heroes when original is hero
@$el.find(".player-hero-icon[data-memberID=#{member.id}]").removeClass('.player-hero-icon').addClass('player-hero-icon ' + slug)
onCampaignSync: ->
return unless @campaigns.loaded
@campaignLevelProgressions = []
for campaign in @campaigns.models
continue if campaign.get('slug') is 'auditions'
campaignLevelProgression =
ID: campaign.id
slug: campaign.get('slug')
name: campaign.get('name')
levels: []
# TODO: Where do these proper names come from?
campaignLevelProgression.name = switch
when campaignLevelProgression.slug is 'dungeon' then 'Kithgard Dungeon'
when campaignLevelProgression.slug is 'forest' then 'Backwoods Forest'
when campaignLevelProgression.slug is 'desert' then 'Sarven Desert'
when campaignLevelProgression.slug is 'mountain' then 'Cloudrip Mountain'
else campaignLevelProgression.name
for levelID, level of campaign.get('levels')
campaignLevelProgression.levels.push
ID: levelID
slug: level.slug
name: level.name
@campaignLevelProgressions.push campaignLevelProgression
@render?()
onClanSync: ->
unless @owner?
@owner = new User _id: @clan.get('ownerID')
@listenTo @owner, 'sync', => @render?()
@supermodel.loadModel @owner, 'owner', cache: false
@render?()
onMembersSync: ->
@stats.averageLevel = Math.round(@members.reduce(((sum, member) -> sum + member.level()), 0) / @members.length)
@render?()
onMemberAchievementsSync: ->
@memberAchievementsMap = {}
for achievement in @memberAchievements.models
user = achievement.get('user')
@memberAchievementsMap[user] ?= []
@memberAchievementsMap[user].push achievement
for user of @memberAchievementsMap
@memberAchievementsMap[user].sort (a, b) -> b.id.localeCompare(a.id)
@stats.averageAchievements = Math.round(@memberAchievements.models.length / Object.keys(@memberAchievementsMap).length)
@render?()
onMemberSessionsSync: ->
@memberLevelMap = {}
2015-04-16 18:26:14 -04:00
memberSessions = {}
for levelSession in @memberSessions.models
continue if levelSession.isMultiplayer()
user = levelSession.get('creator')
levelSlug = levelSession.get('levelID')
@memberLevelMap[user] ?= {}
@memberLevelMap[user][levelSlug] ?= {}
levelInfo =
level: levelSession.get('levelName')
levelID: levelSession.get('levelID')
changed: new Date(levelSession.get('changed')).toLocaleString()
playtime: levelSession.get('playtime')
sessionID: levelSession.id
@memberLevelMap[user][levelSlug].levelInfo = levelInfo
if levelSession.get('state')?.complete is true
@memberLevelMap[user][levelSlug].state = 'complete'
2015-04-16 18:26:14 -04:00
memberSessions[user] ?= []
memberSessions[user].push levelSession
else
@memberLevelMap[user][levelSlug].state = 'started'
2015-04-16 18:26:14 -04:00
@memberMaxLevelCount = 0
@memberLanguageMap = {}
2015-04-16 18:26:14 -04:00
for user of memberSessions
languageCounts = {}
2015-04-16 18:26:14 -04:00
for levelSession in memberSessions[user]
language = levelSession.get('codeLanguage') or levelSession.get('submittedCodeLanguage')
languageCounts[language] = (languageCounts[language] or 0) + 1 if language
2015-04-16 18:26:14 -04:00
@memberMaxLevelCount = memberSessions[user].length if @memberMaxLevelCount < memberSessions[user].length
mostUsedCount = 0
for language, count of languageCounts
if count > mostUsedCount
mostUsedCount = count
@memberLanguageMap[user] = language
@render?()
2015-04-16 18:26:14 -04:00
onMouseEnterPoint: (e) ->
$('.level-popup-container').hide()
2015-04-16 18:26:14 -04:00
container = $(e.target).find('.level-popup-container').show()
margin = 20
offset = $(e.target).offset()
scrollTop = $(e.target).offsetParent().scrollTop()
height = container.outerHeight()
container.css('left', offset.left + e.offsetX)
container.css('top', offset.top + scrollTop - height - margin)
onMouseLeavePoint: (e) ->
$(e.target).find('.level-popup-container').hide()
onClickLevel: (e) ->
levelInfo = $(e.target).data 'level-info'
return unless levelInfo?.levelID? and levelInfo?.sessionID?
url = "/play/level/#{levelInfo.levelID}?session=#{levelInfo.sessionID}&observing=true"
window.open url, '_blank'
2015-04-02 14:44:18 -04:00
onDeleteClan: (e) ->
return @openModalView(new AuthModal()) if me.isAnonymous()
2015-04-21 16:41:31 -04:00
return unless window.confirm("Delete Clan?")
2015-04-02 14:44:18 -04:00
options =
url: "/db/clan/#{@clanID}"
method: 'DELETE'
error: (model, response, options) =>
console.error 'Error joining clan', response
success: (model, response, options) =>
app.router.navigate "/clans"
window.location.reload()
@supermodel.addRequestResource( 'delete_clan', options).load()
onEditDescriptionSave: (e) ->
description = $('.edit-description-input').val()
@clan.set 'description', description
@clan.patch()
$('#editDescriptionModal').modal('hide')
onEditNameSave: (e) ->
if name = $('.edit-name-input').val()
@clan.set 'name', name
@clan.patch()
$('#editNameModal').modal('hide')
onJoinClan: (e) ->
return @openModalView(new AuthModal()) if me.isAnonymous()
return unless @clan.loaded
2015-04-20 17:16:44 -04:00
if @clan.get('type') is 'private' and not me.isPremium()
@openModalView new SubscribeModal()
window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'join clan'
return
2015-04-02 14:44:18 -04:00
options =
url: "/db/clan/#{@clanID}/join"
method: 'PUT'
error: (model, response, options) =>
console.error 'Error joining clan', response
2015-04-03 14:05:37 -04:00
success: (model, response, options) => @refreshData()
2015-04-02 14:44:18 -04:00
@supermodel.addRequestResource( 'join_clan', options).load()
onLeaveClan: (e) ->
2015-04-02 14:44:18 -04:00
options =
url: "/db/clan/#{@clanID}/leave"
method: 'PUT'
error: (model, response, options) =>
console.error 'Error leaving clan', response
2015-04-03 14:05:37 -04:00
success: (model, response, options) => @refreshData()
2015-04-02 14:44:18 -04:00
@supermodel.addRequestResource( 'leave_clan', options).load()
2015-04-02 14:01:37 -04:00
onRemoveMember: (e) ->
2015-04-23 17:33:13 -04:00
return unless window.confirm("Remove Hero?")
2015-04-02 14:01:37 -04:00
if memberID = $(e.target).data('id')
options =
url: "/db/clan/#{@clanID}/remove/#{memberID}"
method: 'PUT'
error: (model, response, options) =>
console.error 'Error removing clan member', response
2015-04-03 14:05:37 -04:00
success: (model, response, options) => @refreshData()
2015-04-02 14:01:37 -04:00
@supermodel.addRequestResource( 'remove_member', options).load()
else
console.error "No member ID attached to remove button."