/*
Copyright 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
const MemberAvatar = require('../avatars/MemberAvatar.js');
module.exports = React.createClass({
displayName: 'MemberEventListSummary',
propTypes: {
// An array of member events to summarise
events: React.PropTypes.array.isRequired,
// An array of EventTiles to render when expanded
children: React.PropTypes.array.isRequired,
// The maximum number of names to show in either each summary e.g. 2 would result "A, B and 234 others left"
summaryLength: React.PropTypes.number,
// The maximum number of avatars to display in the summary
avatarsMaxLength: React.PropTypes.number,
// The minimum number of events needed to trigger summarisation
threshold: React.PropTypes.number,
},
getInitialState: function() {
return {
expanded: false,
};
},
getDefaultProps: function() {
return {
summaryLength: 1,
threshold: 3,
avatarsMaxLength: 5,
};
},
_toggleSummary: function() {
this.setState({
expanded: !this.state.expanded,
});
},
_renderNameList: function(users) {
if (users.length === 0) {
return null;
}
return this._renderCommaSeparatedList(users, this.props.summaryLength);
},
// Test whether the first n items repeat for the duration
// e.g. [1,2,3,4,1,2,3] would resolve true for n = 4
_isRepeatedSequence: function(transitions, n) {
let count = 0;
for (let i = 0; i < transitions.length; i++) {
if (transitions[i % n] !== transitions[i]) {
return null;
}
}
return true;
},
_renderCommaSeparatedList(items, itemLimit) {
const remaining = itemLimit === undefined ? 0 : Math.max(items.length - itemLimit, 0);
if (items.length === 0) {
return "";
} else if (items.length === 1) {
return items[0];
} else if (remaining) {
items = items.slice(0, itemLimit);
const other = " other" + (remaining > 1 ? "s" : "");
return items.join(', ') + ' and ' + remaining + other;
} else {
let last = items.pop();
return items.join(', ') + ' and ' + last;
}
},
_getDescriptionForTransition(t, plural) {
let beConjugated = plural ? "were" : "was";
let invitation = plural ? "invitations" : "an invitation";
switch (t) {
case 'joined': return "joined";
case 'left': return "left";
case 'invite_reject': return "rejected " + invitation;
case 'invite_withdrawal': return "withdrew " + invitation;
case 'invited': return beConjugated + " invited";
case 'banned': return beConjugated + " banned";
case 'unbanned': return beConjugated + " unbanned";
case 'kicked': return beConjugated + " kicked";
}
return null;
},
_renderSummary: function(eventAggregates) {
let summaries = Object.keys(eventAggregates).map((transitions) => {
let nameList = this._renderNameList(eventAggregates[transitions]);
let repeats = 1;
let repeatExtra = 0;
let splitTransitions = transitions.split(',');
let describedTransitions = splitTransitions;
let plural = eventAggregates[transitions].length > 1;
for (let modulus = 1; modulus <= 2; modulus++) {
// Sequences that are repeating through modulus transitions will be truncated
if (this._isRepeatedSequence(describedTransitions, modulus)) {
// Extra repeating sequence on the end that should be treated separately
// so as to avoid j,l,j,l,j => "... joined and left 2.5 times"
repeatExtra = describedTransitions.length % modulus;
repeats = (describedTransitions.length - repeatExtra) / modulus;
describedTransitions = describedTransitions.slice(0, modulus);
break;
}
}
let numberOfTimes = repeats > 1 ? " " + repeats + " times" : "";
let descs = describedTransitions.map((t) => {
return this._getDescriptionForTransition(t, plural);
});
let afterRepeatDescs = splitTransitions.slice(splitTransitions.length - repeatExtra).map((t) => {
return this._getDescriptionForTransition(t, plural);
});
let desc = this._renderCommaSeparatedList(descs);
let afterRepeatDesc = this._renderCommaSeparatedList(afterRepeatDescs);
return nameList + " " + desc + numberOfTimes + (afterRepeatDesc ? " and then " + afterRepeatDesc : "");
});
if (!summaries) {
return null;
}
return (
{summaries.join(", ")}
);
},
_renderAvatars: function(roomMembers) {
let avatars = roomMembers.slice(0, this.props.avatarsMaxLength).map((m) => {
return (