Update private clans dashboard

This commit is contained in:
Matt Lott 2015-04-16 15:26:14 -07:00
parent 2f8831ea72
commit 45c070209b
4 changed files with 142 additions and 46 deletions
app
styles/clans
templates/clans
views/clans
server/clans

View file

@ -25,9 +25,39 @@
$spriteSheetSize: 30px $spriteSheetSize: 30px
td.hero-icon-cell
.remove-hero-cell
width: 100px
.hero-icon-cell
width: 30px width: 30px
.level-cell
width: 50px
text-align: center
.name-cell
width: 100px
.level-progression-cell
background-color: lightblue
border: 1px solid gray
// cursor: pointer
padding: 4px
.level-popup-container
display: none
position: absolute
padding: 10px
border: 1px solid black
z-index: 3
background-color: blanchedalmond
font-size: 10pt
.level-progression-cell-name
background-color: lightblue
border: 1px solid gray
.player-hero-icon .player-hero-icon
background: transparent url(/images/pages/play/play-spritesheet.png) background: transparent url(/images/pages/play/play-spritesheet.png)
background-size: cover background-size: cover

View file

@ -54,7 +54,7 @@ block content
tr tr
td Average Level td Average Level
td= stats.averageLevel td= stats.averageLevel
if stats.totalAchievements if stats.totalAchievements && clan.get('type') === 'public'
tr tr
td Total Achievements td Total Achievements
td= stats.totalAchievements td= stats.totalAchievements
@ -67,40 +67,78 @@ block content
else else
button.btn.btn-lg.btn-success.join-clan-btn Join Clan button.btn.btn-lg.btn-success.join-clan-btn Join Clan
div if clan.get('ownerID') === me.id || clan.get('type') === 'public'
span.spl.spr.join-link-prompt Invite: div
input.join-clan-link(type="text", readonly, value="#{joinClanLink}") span.spl.spr.join-link-prompt Invite:
.small *Invite players to this Clan by sending them this link. input.join-clan-link(type="text", readonly, value="#{joinClanLink}")
.small *Invite players to this Clan by sending them this link.
if members if members
h3 Heroes (#{members.length}) h3 Heroes (#{members.length})
table.table.table-striped.table-condensed if clan.get('type') === 'private'
thead table.table.table-condensed
tr thead
th
th
td Name
th Level
th Achievements
th Latest Achievement
th
tbody
each member in members
tr tr
td.hero-icon-cell if isOwner
span.spr.player-hero-icon(data-memberid="#{member.id}") th
td.code-language-cell th
if memberLanguageMap && memberLanguageMap[member.id] th
span.code-language-cell(style="background-image: url(/images/common/code_languages/#{memberLanguageMap[member.id]}_small.png)", title=memberLanguageMap[member.id]) th Level
td th Name
a(href="/user/#{member.id}")= member.get('name') || 'Anoner' th(colspan="#{memberMaxLevelCount + 1}") Last Level Completed
td= member.level() tbody
td each member in members
if memberAchievementsMap && memberAchievementsMap[member.id] tr
| #{memberAchievementsMap[member.id].length} if isOwner
td td.remove-hero-cell
if memberAchievementsMap && memberAchievementsMap[member.id] && memberAchievementsMap[member.id].length if member.id !== clan.get('ownerID')
span= memberAchievementsMap[member.id][0].get('achievementName') button.btn.btn-xs.btn-warning.remove-member-btn(data-id="#{member.id}") Remove Hero
td td.hero-icon-cell
if isOwner && member.id !== clan.get('ownerID') span.spr.player-hero-icon(data-memberid="#{member.id}")
button.btn.btn-xs.btn-warning.remove-member-btn(data-id="#{member.id}") Remove Hero td.code-language-cell
if memberLanguageMap && memberLanguageMap[member.id]
span.code-language-cell(style="background-image: url(/images/common/code_languages/#{memberLanguageMap[member.id]}_small.png)", title=memberLanguageMap[member.id])
td.level-cell= member.level()
td.name-cell
a(href="/user/#{member.id}")= member.get('name') || 'Anoner'
if memberLevelProgression && memberLevelProgression[member.id]
each levelInfo in memberLevelProgression[member.id]
td.level-progression-cell
.level-popup-container
div Level: #{levelInfo.level}
div Playtime: #{levelInfo.playtime}
div Last played: #{levelInfo.changed}
td(colspan="#{memberMaxLevelCount - memberLevelProgression[member.id].length + 1}")= memberLevelProgression[member.id][memberLevelProgression[member.id].length - 1].level
else
td(colspan="#{memberMaxLevelCount + 1}")
else
table.table.table-striped.table-condensed
thead
tr
th
th
td Name
th Level
th Achievements
th Latest Achievement
th
tbody
each member in members
tr
td.hero-icon-cell
span.spr.player-hero-icon(data-memberid="#{member.id}")
td.code-language-cell
if memberLanguageMap && memberLanguageMap[member.id]
span.code-language-cell(style="background-image: url(/images/common/code_languages/#{memberLanguageMap[member.id]}_small.png)", title=memberLanguageMap[member.id])
td
a(href="/user/#{member.id}")= member.get('name') || 'Anoner'
td= member.level()
td
if memberAchievementsMap && memberAchievementsMap[member.id]
| #{memberAchievementsMap[member.id].length}
td
if memberAchievementsMap && memberAchievementsMap[member.id] && memberAchievementsMap[member.id].length
span= memberAchievementsMap[member.id][0].get('achievementName')
td
if isOwner && member.id !== clan.get('ownerID')
button.btn.btn-xs.btn-warning.remove-member-btn(data-id="#{member.id}") Remove Hero

View file

@ -24,6 +24,8 @@ module.exports = class ClanDetailsView extends RootView
'click .join-clan-btn': 'onJoinClan' 'click .join-clan-btn': 'onJoinClan'
'click .leave-clan-btn': 'onLeaveClan' 'click .leave-clan-btn': 'onLeaveClan'
'click .remove-member-btn': 'onRemoveMember' 'click .remove-member-btn': 'onRemoveMember'
'mouseenter .level-progression-cell': 'onMouseEnterPoint'
'mouseleave .level-progression-cell': 'onMouseLeavePoint'
constructor: (options, @clanID) -> constructor: (options, @clanID) ->
super options super options
@ -61,6 +63,8 @@ module.exports = class ClanDetailsView extends RootView
context.owner = @owner context.owner = @owner
context.memberAchievementsMap = @memberAchievementsMap context.memberAchievementsMap = @memberAchievementsMap
context.memberLanguageMap = @memberLanguageMap context.memberLanguageMap = @memberLanguageMap
context.memberLevelProgression = @memberLevelProgression
context.memberMaxLevelCount = @memberMaxLevelCount
context.members = @members?.models context.members = @members?.models
context.isOwner = @clan.get('ownerID') is me.id context.isOwner = @clan.get('ownerID') is me.id
context.isMember = @clanID in (me.get('clans') ? []) context.isMember = @clanID in (me.get('clans') ? [])
@ -75,6 +79,7 @@ module.exports = class ClanDetailsView extends RootView
me.fetch cache: false me.fetch cache: false
@members.fetch cache: false @members.fetch cache: false
@memberAchievements.fetch cache: false @memberAchievements.fetch cache: false
@memberSessions.fetch cache: false
updateHeroIcons: -> updateHeroIcons: ->
return unless @members?.models? return unless @members?.models?
@ -106,17 +111,27 @@ module.exports = class ClanDetailsView extends RootView
@render?() @render?()
onMemberSessionsSync: -> onMemberSessionsSync: ->
@memberSessionMap = {} @memberLevelProgression = {}
memberSessions = {}
for levelSession in @memberSessions.models for levelSession in @memberSessions.models
user = levelSession.get('creator') user = levelSession.get('creator')
@memberSessionMap[user] ?= [] if not levelSession.isMultiplayer() and levelSession.get('state')?.complete is true
@memberSessionMap[user].push levelSession memberSessions[user] ?= []
memberSessions[user].push levelSession
@memberLevelProgression[user] ?= []
levelInfo =
level: levelSession.get('levelName')
changed: new Date(levelSession.get('changed')).toLocaleString()
playtime: levelSession.get('playtime')
@memberLevelProgression[user].push levelInfo
@memberMaxLevelCount = 0
@memberLanguageMap = {} @memberLanguageMap = {}
for user of @memberSessionMap for user of memberSessions
languageCounts = {} languageCounts = {}
for levelSession in @memberSessionMap[user] for levelSession in memberSessions[user]
language = levelSession.get('codeLanguage') or levelSession.get('submittedCodeLanguage') language = levelSession.get('codeLanguage') or levelSession.get('submittedCodeLanguage')
languageCounts[language] = (languageCounts[language] or 0) + 1 if language languageCounts[language] = (languageCounts[language] or 0) + 1 if language
@memberMaxLevelCount = memberSessions[user].length if @memberMaxLevelCount < memberSessions[user].length
mostUsedCount = 0 mostUsedCount = 0
for language, count of languageCounts for language, count of languageCounts
if count > mostUsedCount if count > mostUsedCount
@ -124,6 +139,18 @@ module.exports = class ClanDetailsView extends RootView
@memberLanguageMap[user] = language @memberLanguageMap[user] = language
@render?() @render?()
onMouseEnterPoint: (e) ->
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()
onDeleteClan: (e) -> onDeleteClan: (e) ->
return @openModalView(new AuthModal()) if me.isAnonymous() return @openModalView(new AuthModal()) if me.isAnonymous()
options = options =

View file

@ -68,7 +68,7 @@ ClanHandler = class ClanHandler extends Handler
return @sendNotFoundError(res, err) return @sendNotFoundError(res, err)
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendDatabaseError(res, err) unless clan return @sendNotFoundError(res) unless clan
return @sendDatabaseError(res, err) unless clanType = clan.get('type') return @sendDatabaseError(res, err) unless clanType = clan.get('type')
return @sendForbiddenError(res) unless clanType is 'public' or req.user.isPremium() return @sendForbiddenError(res) unless clanType is 'public' or req.user.isPremium()
Clan.update {_id: clanID}, {$addToSet: {members: req.user._id}}, (err) => Clan.update {_id: clanID}, {$addToSet: {members: req.user._id}}, (err) =>
@ -86,7 +86,7 @@ ClanHandler = class ClanHandler extends Handler
return @sendNotFoundError(res, err) return @sendNotFoundError(res, err)
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendDatabaseError(res, err) unless clan return @sendNotFoundError(res) unless clan
return @sendForbiddenError(res) if clan.get('ownerID')?.equals req.user._id return @sendForbiddenError(res) if clan.get('ownerID')?.equals req.user._id
Clan.update {_id: clanID}, {$pull: {members: req.user._id}}, (err) => Clan.update {_id: clanID}, {$pull: {members: req.user._id}}, (err) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
@ -99,7 +99,7 @@ ClanHandler = class ClanHandler extends Handler
# TODO: add tests # TODO: add tests
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendDatabaseError(res, err) unless clan return @sendNotFoundError(res) unless clan
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
EarnedAchievement.find {user: {$in: memberIDs}}, (err, documents) => EarnedAchievement.find {user: {$in: memberIDs}}, (err, documents) =>
return @sendDatabaseError(res, err) if err? return @sendDatabaseError(res, err) if err?
@ -110,7 +110,7 @@ ClanHandler = class ClanHandler extends Handler
# TODO: add tests # TODO: add tests
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendDatabaseError(res, err) unless clan return @sendNotFoundError(res) unless clan
memberIDs = clan.get('members') ? [] memberIDs = clan.get('members') ? []
User.find {_id: {$in: memberIDs}}, (err, users) => User.find {_id: {$in: memberIDs}}, (err, users) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
@ -119,9 +119,10 @@ ClanHandler = class ClanHandler extends Handler
getMemberSessions: (req, res, clanID) -> getMemberSessions: (req, res, clanID) ->
# TODO: add tests # TODO: add tests
# TODO: restrict information returned based on clan type
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendDatabaseError(res, err) unless clan return @sendNotFoundError(res) unless clan
memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID
LevelSession.find {creator: {$in: memberIDs}}, (err, documents) => LevelSession.find {creator: {$in: memberIDs}}, (err, documents) =>
return @sendDatabaseError(res, err) if err? return @sendDatabaseError(res, err) if err?
@ -147,7 +148,7 @@ ClanHandler = class ClanHandler extends Handler
return @sendNotFoundError(res, err) return @sendNotFoundError(res, err)
Clan.findById clanID, (err, clan) => Clan.findById clanID, (err, clan) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendDatabaseError(res, err) unless clan return @sendNotFoundError(res) unless clan
return @sendForbiddenError res unless @hasAccessToDocument(req, clan) return @sendForbiddenError res unless @hasAccessToDocument(req, clan)
return @sendForbiddenError(res) if clan.get('ownerID').equals memberID return @sendForbiddenError(res) if clan.get('ownerID').equals memberID
Clan.update {_id: clanID}, {$pull: {members: memberID}}, (err) => Clan.update {_id: clanID}, {$pull: {members: memberID}}, (err) =>