Channel members fix (#209)

* Channel members fix

* Review feedback
This commit is contained in:
Chris Duarte 2017-02-01 06:28:01 -08:00 committed by Harrison Healey
parent 1bd40d1a40
commit ea3b2cabd4
7 changed files with 62 additions and 30 deletions

View file

@ -12,12 +12,17 @@ import {
import Client from 'service/client';
import {displayUsername} from 'service/utils/user_utils';
import FormattedText from 'app/components/formatted_text';
import MemberListRow from './member_list_row';
const style = StyleSheet.create({
listView: {
flex: 1
},
loadingText: {
opacity: 0.6
},
sectionContainer: {
backgroundColor: '#eaeaea',
paddingLeft: 10,
@ -40,13 +45,20 @@ export default class MemberList extends PureComponent {
onListEndReached: PropTypes.func,
onListEndReachedThreshold: PropTypes.number,
sections: PropTypes.bool,
preferences: PropTypes.object
preferences: PropTypes.object,
loadingMembers: PropTypes.bool,
listPageSize: PropTypes.number,
listInitialSize: PropTypes.number,
listScrollRenderAheadDistance: PropTypes.number
}
static defaultProps = {
onListEndReached: () => true,
onListEndThreshold: 10,
sections: true
onListEndThreshold: 50,
sections: true,
listPageSize: 10,
listInitialSize: 10,
listScrollRenderAheadDistance: 200
}
constructor(props) {
@ -73,7 +85,7 @@ export default class MemberList extends PureComponent {
createSections = (data) => {
const sections = {};
data.forEach((d) => {
const name = displayUsername(d, this.props.preferences);
const name = d.username;
const sectionKey = name.substring(0, 1).toUpperCase();
if (!sections[sectionKey]) {
@ -87,6 +99,10 @@ export default class MemberList extends PureComponent {
}
renderSectionHeader = (sectionData, sectionId) => {
if (!this.props.sections) {
return null;
}
return (
<View style={style.sectionContainer}>
<Text style={style.sectionText}>{sectionId}</Text>
@ -111,7 +127,7 @@ export default class MemberList extends PureComponent {
);
}
renderSeparator(sectionId, rowId) {
renderSeparator = (sectionId, rowId) => {
return (
<View
key={`${sectionId}-${rowId}`}
@ -120,6 +136,24 @@ export default class MemberList extends PureComponent {
);
}
renderFooter = () => {
if (!this.props.loadingMembers) {
return null;
}
const backgroundColor = this.props.members.length > 0 ? '#fff' : '#0000';
return (
<View style={{height: 70, backgroundColor, alignItems: 'center', justifyContent: 'center'}}>
<FormattedText
id='mobile.components.member_list.loading_members'
defaultMessage='Loading Members...'
style={style.loadingText}
/>
</View>
);
}
render() {
return (
<ListView
@ -128,9 +162,13 @@ export default class MemberList extends PureComponent {
renderRow={this.renderRow}
renderSectionHeader={this.renderSectionHeader}
renderSeparator={this.renderSeparator}
renderFooter={this.renderFooter}
enableEmptySections={true}
onEndReached={this.props.onListEndReached}
onEndReachedThreshold={this.props.onListEndReachedThreshold}
pageSize={this.props.listPageSize}
initialListSize={this.props.listInitialSize}
scrollRenderAheadDistance={this.props.listScrollRenderAheadDistance}
/>
);
}

View file

@ -8,6 +8,8 @@ import {
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
const placeholder = require('assets/images/profile.jpg');
const style = StyleSheet.create({
avatar: {
height: 40,
@ -96,6 +98,7 @@ function MemberListRow(props) {
<Image
style={style.avatar}
source={{uri: pictureURL}}
defaultSource={placeholder}
/>
<View style={[style.statusContainer, style[status]]}>
{StatusComponent}

View file

@ -3,6 +3,7 @@
import React, {PropTypes, PureComponent} from 'react';
import {
InteractionManager,
StyleSheet,
View
} from 'react-native';
@ -19,29 +20,25 @@ export default class ChannelMembers extends PureComponent {
static propTypes = {
currentChannel: PropTypes.object,
currentChannelMembers: PropTypes.array.isRequired,
currentChannelMemberCount: PropTypes.number.isRequired,
currentTeam: PropTypes.object,
preferences: PropTypes.object,
requestStatus: PropTypes.string,
actions: PropTypes.shape({
getProfilesInChannel: PropTypes.func.isRequired
})
}
state = {
currentChannelMemberCount: 0
}
componentDidMount() {
this.props.actions.getProfilesInChannel(this.props.currentTeam.id, this.props.currentChannel.id, 0);
}
componentWillReceiveProps(nextProps) {
this.setState({
currentChannelMemberCount: this.state.currentChannelMemberCount + nextProps.currentChannelMembers.length
InteractionManager.runAfterInteractions(() => {
this.props.actions.getProfilesInChannel(this.props.currentTeam.id, this.props.currentChannel.id, 0);
});
}
loadMoreMembers = () => {
this.props.actions.getProfilesInChannel(this.props.currentTeam.id, this.props.currentChannel.id, this.state.currentChannelMemberCount);
if (this.props.requestStatus !== 'started' && this.props.currentChannelMembers.length < this.props.currentChannelMemberCount) {
this.props.actions.getProfilesInChannel(this.props.currentTeam.id, this.props.currentChannel.id, this.props.currentChannelMembers.length);
}
}
render() {
@ -51,6 +48,7 @@ export default class ChannelMembers extends PureComponent {
members={this.props.currentChannelMembers}
onListEndReached={this.loadMoreMembers}
preferences={this.props.preferences}
loadingMembers={this.props.requestStatus === 'started'}
/>
</View>
);

View file

@ -20,7 +20,8 @@ function mapStateToProps(state) {
currentChannelMembers: getProfilesInCurrentChannel(state),
currentChannelMemberCount,
currentTeam: getCurrentTeam(state),
preferences: getMyPreferences(state)
preferences: getMyPreferences(state),
requestStatus: state.requests.users.getProfilesInChannel.status
};
}

View file

@ -1492,6 +1492,7 @@
"mobile.channel_list.privateChannel": "Private Channel",
"mobile.channel_list.publicChannel": "Public Channel",
"mobile.components.channels_list_view.yourChannels": "Your channels:",
"mobile.components.member_list.loading_members": "Loading Members...",
"mobile.components.select_server_view.enterServerUrl": "Enter Server URL",
"mobile.components.select_server_view.continue": "Continue",
"mobile.components.select_server_view.siteUrlPlaceholder": "https://mattermost.example.com",

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -5,7 +5,6 @@ import {createSelector} from 'reselect';
import {getCurrentChannelId} from './channels';
import {getMyPreferences} from './preferences';
import {displayUsername} from 'service/utils/user_utils';
export function getCurrentUserId(state) {
return state.entities.users.currentId;
@ -48,7 +47,7 @@ export const getProfilesInCurrentChannel = createSelector(
getUserStatuses,
getProfileSetInCurrentChannel,
getMyPreferences,
(profiles, statuses, currentChannelProfileSet, preferences) => {
(profiles, statuses, currentChannelProfileSet) => {
const currentProfiles = [];
if (typeof currentChannelProfileSet === 'undefined') {
return currentProfiles;
@ -61,19 +60,11 @@ export const getProfilesInCurrentChannel = createSelector(
});
});
// We could get rid of this if server side sorting is a possibility
const sortedCurrentProfiles = currentProfiles.sort((a, b) => {
const nameA = displayUsername(a, preferences);
const nameB = displayUsername(b, preferences);
const nameA = a.username;
const nameB = b.username;
if (nameA.toUpperCase() < nameB.toUpperCase()) {
return -1;
}
if (nameA.toUpperCase() > nameB.toUpperCase()) {
return 1;
}
return 0;
return nameA.localeCompare(nameB);
});
return sortedCurrentProfiles;