Commit 0e180bd2 by Daniel Friedman

Add membership thumbnails to team cards.

TNL-3172
parent 7b77f816
......@@ -35,8 +35,8 @@ class UserMembershipSerializer(serializers.ModelSerializer):
class Meta(object):
"""Defines meta information for the ModelSerializer."""
model = CourseTeamMembership
fields = ("user", "date_joined")
read_only_fields = ("date_joined",)
fields = ("user", "date_joined", "last_activity_at")
read_only_fields = ("date_joined", "last_activity_at")
class CourseTeamSerializer(serializers.ModelSerializer):
......
......@@ -14,7 +14,7 @@
this.server_api = _.extend(
{
expand: 'team',
expand: 'team,user',
username: this.username,
course_id: function () { return encodeURIComponent(self.course_id); }
},
......
......@@ -7,11 +7,12 @@
var TeamMembership = Backbone.Model.extend({
defaults: {
date_joined: '',
last_activity_at: '',
team: null,
user: null
},
parse: function (response, options) {
parse: function (response) {
response.team = new TeamModel(response.team);
return response;
}
......
......@@ -65,7 +65,7 @@ define([
requests,
TeamSpecHelpers.testContext.teamMembershipsUrl,
{
expand : 'team',
expand : 'team,user',
username : TeamSpecHelpers.testContext.userInfo.username,
course_id : TeamSpecHelpers.testContext.courseID,
page : '1',
......
......@@ -3,21 +3,24 @@ define(['jquery',
'teams/js/views/team_card',
'teams/js/models/team'],
function ($, _, TeamCardView, Team) {
'use strict';
describe('TeamCardView', function () {
var createTeamCardView, view;
createTeamCardView = function () {
var model = new Team({
id: 'test-team',
name: 'Test Team',
is_active: true,
course_id: 'test/course/id',
topic_id: 'test-topic',
description: 'A team for testing',
last_activity_at: "2015-08-21T18:53:01.145Z",
country: 'us',
language: 'en'
}),
teamCardClass = TeamCardView.extend({
id: 'test-team',
name: 'Test Team',
is_active: true,
course_id: 'test/course/id',
topic_id: 'test-topic',
description: 'A team for testing',
last_activity_at: "2015-08-21T18:53:01.145Z",
country: 'us',
language: 'en',
membership: []
}),
TeamCardClass = TeamCardView.extend({
maxTeamSize: '100',
srInfo: {
id: 'test-sr-id',
......@@ -26,7 +29,7 @@ define(['jquery',
countries: {us: 'United States of America'},
languages: {en: 'English'}
});
return new teamCardClass({
return new TeamCardClass({
model: model
});
};
......@@ -50,6 +53,101 @@ define(['jquery',
it('navigates to the associated team page when its action button is clicked', function () {
expect(view.$('.action').attr('href')).toEqual('#teams/test-topic/test-team');
});
describe('Profile Image Thumbnails', function () {
/**
* Takes an array of objects representing team
* members, each having the keys 'username',
* 'image_url', and 'last_activity', and sets the
* teams membership accordingly and re-renders the
* view.
*/
var setMemberships, expectThumbnailsOrder;
setMemberships = function (memberships) {
view.model.set({
membership: _.map(memberships, function (m) {
return {
user: {username: m.username, profile_image: {image_url_small: m.image_url}},
last_activity_at: m.last_activity
};
})
});
view.render();
};
/**
* Takes an array of objects representing team
* members, each having the keys 'username' and
* 'image_url', and expects that the image thumbnails
* rendered on the team card match, in order, the
* members of the provided list.
*/
expectThumbnailsOrder = function (members) {
var thumbnails = view.$('.item-member-thumb img');
expect(thumbnails.length).toBe(members.length);
thumbnails.each(function (index, imgEl) {
expect(thumbnails.eq(index).attr('alt')).toBe(members[index].username);
expect(thumbnails.eq(index).attr('src')).toBe(members[index].image_url);
});
};
it('displays no thumbnails for an empty team', function () {
view.model.set({membership: []});
view.render();
expect(view.$('.item-member-thumb').length).toBe(0);
});
it('displays thumbnails for a nonempty team', function () {
var users = [
{
username: 'user_1', image_url: 'user_1_image',
last_activity: new Date("2010/1/1").toString()
}, {
username: 'user_2', image_url: 'user_2_image',
last_activity: new Date("2011/1/1").toString()
}
];
setMemberships(users);
expectThumbnailsOrder([
{username: 'user_2', image_url: 'user_2_image'},
{username: 'user_1', image_url: 'user_1_image'},
]);
});
it('displays thumbnails and an ellipsis for a team with greater than 5 members', function () {
var users = [
{
username: 'user_1', image_url: 'user_1_image',
last_activity: new Date("2001/1/1").toString()
}, {
username: 'user_2', image_url: 'user_2_image',
last_activity: new Date("2006/1/1").toString()
}, {
username: 'user_3', image_url: 'user_3_image',
last_activity: new Date("2003/1/1").toString()
}, {
username: 'user_4', image_url: 'user_4_image',
last_activity: new Date("2002/1/1").toString()
}, {
username: 'user_5', image_url: 'user_5_image',
last_activity: new Date("2005/1/1").toString()
}, {
username: 'user_6', image_url: 'user_6_image',
last_activity: new Date("2004/1/1").toString()
}
];
setMemberships(users);
expectThumbnailsOrder([
{username: 'user_2', image_url: 'user_2_image'},
{username: 'user_5', image_url: 'user_5_image'},
{username: 'user_6', image_url: 'user_6_image'},
{username: 'user_3', image_url: 'user_3_image'},
{username: 'user_4', image_url: 'user_4_image'},
]);
expect(view.$('.item-member-thumb').eq(-1)).toHaveText('and others…');
});
});
});
}
);
......@@ -7,34 +7,43 @@
'jquery.timeago',
'js/components/card/views/card',
'teams/js/views/team_utils',
'text!teams/templates/team-membership-details.underscore',
'text!teams/templates/team-country-language.underscore',
'text!teams/templates/team-activity.underscore'
], function (Backbone, _, gettext, timeago, CardView, TeamUtils, teamCountryLanguageTemplate, teamActivityTemplate) {
], function (
Backbone,
_,
gettext,
timeago,
CardView,
TeamUtils,
teamMembershipDetailsTemplate,
teamCountryLanguageTemplate,
teamActivityTemplate
) {
var TeamMembershipView, TeamCountryLanguageView, TeamActivityView, TeamCardView;
TeamMembershipView = Backbone.View.extend({
tagName: 'div',
className: 'team-members',
template: _.template(
'<span class="member-count"><%= membership_message %></span>' +
'<ul class="list-member-thumbs"></ul>'
),
template: _.template(teamMembershipDetailsTemplate),
initialize: function (options) {
this.maxTeamSize = options.maxTeamSize;
},
render: function () {
var memberships = this.model.get('membership'),
var allMemberships = _(this.model.get('membership'))
.sortBy(function (member) {return new Date(member.last_activity_at);}).reverse(),
displayableMemberships = allMemberships.slice(0, 5),
maxMemberCount = this.maxTeamSize;
this.$el.html(this.template({
membership_message: TeamUtils.teamCapacityText(memberships.length, maxMemberCount)
membership_message: TeamUtils.teamCapacityText(allMemberships.length, maxMemberCount),
memberships: displayableMemberships,
has_additional_memberships: displayableMemberships.length < allMemberships.length,
// Translators: "and others" refers to fact that additional members of a team exist that are not displayed.
sr_message: gettext('and others')
}));
_.each(memberships, function (membership) {
this.$('list-member-thumbs').append(
'<li class="item-member-thumb"><img alt="' + membership.user.username + '" src=""></img></li>'
);
}, this);
return this;
}
});
......
<span class="member-count"><%= membership_message %></span>
<ul class="list-member-thumbs">
<% _.each(memberships, function (membership) { %>
<li class="item-member-thumb"><img alt="<%- membership.user.username %>" src="<%- membership.user.profile_image.image_url_small %>"></img></li>
<% }) %>
<% if (has_additional_memberships) { %>
<li class="item-member-thumb"><span class="sr"><%- sr_message %></span>&hellip;</li>
<% } %>
</ul>
......@@ -97,7 +97,7 @@ class TeamsDashboardView(View):
team_memberships_page = Paginator(team_memberships, TEAM_MEMBERSHIPS_PER_PAGE).page(1)
team_memberships_serializer = PaginatedMembershipSerializer(
instance=team_memberships_page,
context={'expand': ('team',)},
context={'expand': ('team', 'user'), 'request': request},
)
context = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment